119 lines
3.6 KiB
Python
Executable file
119 lines
3.6 KiB
Python
Executable file
#!/usr/bin/env python
|
|
import subprocess
|
|
import os
|
|
import sys
|
|
import re
|
|
from urllib.parse import urlsplit
|
|
|
|
extract_line_regex = re.compile(r"(.*?)(?::([0-9]+))?(?::([0-9]+))?(:)?$")
|
|
|
|
main_editor = "nvim"
|
|
editors = [main_editor, "vim", "vi"]
|
|
real_editor = os.environ.get("REAL_EDITOR", None)
|
|
editor_command = main_editor
|
|
if real_editor is not None:
|
|
editors.append(real_editor)
|
|
editor_command = real_editor
|
|
|
|
def run(cmd, only_stdout=True):
|
|
res = subprocess.run(cmd, capture_output=True, text=True, shell=True)
|
|
if only_stdout:
|
|
return str(res.stdout)
|
|
else:
|
|
return res
|
|
|
|
def find_pane(window):
|
|
for editor in editors:
|
|
pane = run(f"tmux list-panes -a -f '#{{&&:#{{==:#{{window_id}},{window}}},#{{==:#{{pane_current_command}},{editor}}}}}' -F '#{{pane_id}}'").strip();
|
|
if pane != "":
|
|
return pane
|
|
|
|
def create_pane(args):
|
|
run(f'tmux split-window -h -P -F "#{{pane_id}}" {editor_command} {args}')
|
|
|
|
def find_or_create_pane(window, args):
|
|
if pane := find_pane(window):
|
|
# exit copy mode so we don't send these commands directly to tmux
|
|
run(f"tmux send-keys -t {pane} -X cancel")
|
|
# Escape for some reason doesn't get sent as the escape key if it shows up next to any other keys???
|
|
run(f"tmux send-keys -t {pane} Escape")
|
|
|
|
# note the space, this tells nvim not to save it in history
|
|
run(f"tmux send-keys -t {pane} \": drop {args}\" Enter")
|
|
run(f"tmux select-pane -t {pane} -Z")
|
|
else:
|
|
create_pane(args)
|
|
|
|
def split_line(filename):
|
|
mtch = extract_line_regex.match(filename)
|
|
file = mtch.group(1)
|
|
line = mtch.group(2)
|
|
column = mtch.group(3)
|
|
|
|
url = urlsplit(line)
|
|
if url.scheme == "file" and url.path != file:
|
|
file = url.path
|
|
|
|
file = os.path.abspath(file)
|
|
|
|
print(f"opening {file}:{line}:{column}")
|
|
return file, line, column
|
|
|
|
def join_line(filename, maybe_line, maybe_column):
|
|
assert not (maybe_line is None and maybe_column is not None)
|
|
|
|
if maybe_line is None:
|
|
return filename
|
|
|
|
if maybe_column is None:
|
|
maybe_column = "0"
|
|
|
|
return f"+normal!{maybe_line}G{maybe_column} {filename}"
|
|
|
|
def trim(arg):
|
|
if arg.startswith("\"") and not arg.endswith("\""):
|
|
arg = arg.lstrip("\"")
|
|
if arg.endswith("\"") and not arg.startswith("\""):
|
|
arg = arg.rstrip("\"")
|
|
return arg.strip()
|
|
|
|
def editor_hax(filename):
|
|
args = split_line(trim(filename))
|
|
current_window = run("tmux display-message -p \"#{window_id}\"").strip();
|
|
find_or_create_pane(current_window, join_line(*args))
|
|
|
|
def xdg_open(arg):
|
|
subprocess.run(f"xdg-open {trim(arg)}", shell=True)
|
|
|
|
def xdg_open_proxy(*args):
|
|
for arg in args:
|
|
try:
|
|
_file, line, _column = split_line(arg)
|
|
if line is not None:
|
|
editor_hax(arg)
|
|
else:
|
|
xdg_open(arg)
|
|
except:
|
|
xdg_open(arg)
|
|
|
|
|
|
def usage():
|
|
print(f"usage: {sys.argv[0]} filename:(line):(column)")
|
|
print(" Opens a file with line number and colum in the editor in another pane of the current tmux window")
|
|
print(f"usage: {sys.argv[0]} xdg-open-proxy filename:(line):(column)")
|
|
print(" Calls xdg-open on the given parameters. However, if any part contains a line number and or column, opens in nvim like editor-hax")
|
|
exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) < 2:
|
|
usage()
|
|
elif sys.argv[1] == "xdg-open-proxy":
|
|
if len(sys.argv) < 3:
|
|
usage()
|
|
else:
|
|
xdg_open_proxy(*sys.argv[1:])
|
|
elif len(sys.argv) > 2:
|
|
usage()
|
|
else:
|
|
editor_hax(sys.argv[1])
|
|
|