Command line tools shouldnt need to resolve documentation refs
Instead use a new kitty+doc protocol and have kitty navigate to the docs. Uses a default open action for the protocol, which can be overriden by the user should they so desire.
This commit is contained in:
parent
0b66f20934
commit
314dd97059
@ -64,6 +64,10 @@ some special variables, documented below:
|
|||||||
``FRAGMENT``
|
``FRAGMENT``
|
||||||
The fragment (unquoted), if any of the URL or the empty string.
|
The fragment (unquoted), if any of the URL or the empty string.
|
||||||
|
|
||||||
|
``URL_PATH``
|
||||||
|
The path, query and fragment portions of the URL, without any
|
||||||
|
unquoting.
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
You can use the :opt:`action_alias` option just as in :file:`kitty.conf` to
|
You can use the :opt:`action_alias` option just as in :file:`kitty.conf` to
|
||||||
|
|||||||
26
kitty/cli.py
26
kitty/cli.py
@ -11,12 +11,12 @@ from typing import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from .cli_stub import CLIOptions
|
from .cli_stub import CLIOptions
|
||||||
from .conf.types import resolve_ref
|
|
||||||
from .conf.utils import resolve_config
|
from .conf.utils import resolve_config
|
||||||
from .constants import (
|
from .constants import (
|
||||||
appname, clear_handled_signals, defconf, is_macos, str_version, website_url
|
appname, clear_handled_signals, defconf, is_macos, str_version, website_url
|
||||||
)
|
)
|
||||||
from .options.types import Options as KittyOpts
|
from .options.types import Options as KittyOpts
|
||||||
|
from .types import run_once
|
||||||
from .typing import BadLineType, TypedDict
|
from .typing import BadLineType, TypedDict
|
||||||
|
|
||||||
|
|
||||||
@ -171,22 +171,26 @@ def doc(x: str) -> str:
|
|||||||
return website_url(x)
|
return website_url(x)
|
||||||
|
|
||||||
|
|
||||||
|
@run_once
|
||||||
|
def hostname() -> str:
|
||||||
|
import socket
|
||||||
|
return socket.gethostname() or 'localhost'
|
||||||
|
|
||||||
|
|
||||||
|
def ref_hyperlink(x: str, prefix: str = '') -> str:
|
||||||
|
t, q = text_and_target(x)
|
||||||
|
url = f'kitty+doc://{hostname()}/#ref={prefix}{q}'
|
||||||
|
return hyperlink_for_url(url, t)
|
||||||
|
|
||||||
|
|
||||||
@role
|
@role
|
||||||
def ref(x: str) -> str:
|
def ref(x: str) -> str:
|
||||||
t, q = text_and_target(x)
|
return ref_hyperlink(x)
|
||||||
url = resolve_ref(q)
|
|
||||||
if url:
|
|
||||||
return hyperlink_for_url(url, t)
|
|
||||||
return t
|
|
||||||
|
|
||||||
|
|
||||||
@role
|
@role
|
||||||
def ac(x: str) -> str:
|
def ac(x: str) -> str:
|
||||||
t, q = text_and_target(x)
|
return ref_hyperlink(x, 'action-')
|
||||||
url = resolve_ref(q)
|
|
||||||
if url:
|
|
||||||
return hyperlink_for_url(url, t)
|
|
||||||
return t
|
|
||||||
|
|
||||||
|
|
||||||
OptionSpecSeq = List[Union[str, OptionDict]]
|
OptionSpecSeq = List[Union[str, OptionDict]]
|
||||||
|
|||||||
@ -75,7 +75,7 @@ def parse(lines: Iterable[str]) -> Iterator[OpenAction]:
|
|||||||
entries.append((tuple(match_criteria), tuple(raw_actions)))
|
entries.append((tuple(match_criteria), tuple(raw_actions)))
|
||||||
|
|
||||||
with to_cmdline_implementation.filter_env_vars(
|
with to_cmdline_implementation.filter_env_vars(
|
||||||
'URL', 'FILE_PATH', 'FILE', 'FRAGMENT',
|
'URL', 'FILE_PATH', 'FILE', 'FRAGMENT', 'URL_PATH',
|
||||||
EDITOR=shlex.join(get_editor()),
|
EDITOR=shlex.join(get_editor()),
|
||||||
SHELL=shlex.join(resolved_shell(get_options()))
|
SHELL=shlex.join(resolved_shell(get_options()))
|
||||||
):
|
):
|
||||||
@ -97,7 +97,7 @@ def url_matches_criterion(purl: 'ParseResult', url: str, unquoted_path: str, mc:
|
|||||||
|
|
||||||
if mc.type == 'mime':
|
if mc.type == 'mime':
|
||||||
import fnmatch
|
import fnmatch
|
||||||
mt = guess_type(unquoted_path, allow_filesystem_access=True)
|
mt = guess_type(unquoted_path, allow_filesystem_access=purl.scheme in ('', 'file'))
|
||||||
if not mt:
|
if not mt:
|
||||||
return False
|
return False
|
||||||
mt = mt.lower()
|
mt = mt.lower()
|
||||||
@ -169,10 +169,16 @@ def actions_for_url_from_list(url: str, actions: Iterable[OpenAction]) -> Iterat
|
|||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
path = unquote(purl.path)
|
path = unquote(purl.path)
|
||||||
|
up = purl.path
|
||||||
|
if purl.query:
|
||||||
|
up += f'?{purl.query}'
|
||||||
|
if purl.fragment:
|
||||||
|
up += f'#{purl.fragment}'
|
||||||
|
|
||||||
env = {
|
env = {
|
||||||
'URL': url,
|
'URL': url,
|
||||||
'FILE_PATH': path,
|
'FILE_PATH': path,
|
||||||
|
'URL_PATH': up,
|
||||||
'FILE': posixpath.basename(path),
|
'FILE': posixpath.basename(path),
|
||||||
'FRAGMENT': unquote(purl.fragment)
|
'FRAGMENT': unquote(purl.fragment)
|
||||||
}
|
}
|
||||||
@ -215,6 +221,15 @@ def load_launch_actions() -> Tuple[OpenAction, ...]:
|
|||||||
return tuple(parse(f))
|
return tuple(parse(f))
|
||||||
|
|
||||||
|
|
||||||
|
@run_once
|
||||||
|
def default_open_actions() -> Tuple[OpenAction, ...]:
|
||||||
|
return tuple(parse('''\
|
||||||
|
# Open kitty HTML docs links
|
||||||
|
protocol kitty+doc
|
||||||
|
action show_kitty_doc $URL_PATH
|
||||||
|
'''.splitlines()))
|
||||||
|
|
||||||
|
|
||||||
@run_once
|
@run_once
|
||||||
def default_launch_actions() -> Tuple[OpenAction, ...]:
|
def default_launch_actions() -> Tuple[OpenAction, ...]:
|
||||||
SHELL = resolved_shell(get_options())
|
SHELL = resolved_shell(get_options())
|
||||||
@ -260,7 +275,12 @@ def actions_for_url(url: str, actions_spec: Optional[str] = None) -> Iterator[Ke
|
|||||||
actions = load_open_actions()
|
actions = load_open_actions()
|
||||||
else:
|
else:
|
||||||
actions = tuple(parse(actions_spec.splitlines()))
|
actions = tuple(parse(actions_spec.splitlines()))
|
||||||
yield from actions_for_url_from_list(url, actions)
|
found = False
|
||||||
|
for action in actions_for_url_from_list(url, actions):
|
||||||
|
found = True
|
||||||
|
yield action
|
||||||
|
if not found:
|
||||||
|
yield from actions_for_url_from_list(url, default_open_actions())
|
||||||
|
|
||||||
|
|
||||||
def actions_for_launch(url: str) -> Iterator[KeyAction]:
|
def actions_for_launch(url: str) -> Iterator[KeyAction]:
|
||||||
|
|||||||
@ -1074,8 +1074,15 @@ def safer_fork() -> int:
|
|||||||
def docs_url(which: str = '', local_docs_root: str = '') -> str:
|
def docs_url(which: str = '', local_docs_root: str = '') -> str:
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
from .constants import local_docs, website_url
|
from .constants import local_docs, website_url
|
||||||
|
from .conf.types import resolve_ref
|
||||||
ld = local_docs_root or local_docs()
|
ld = local_docs_root or local_docs()
|
||||||
base, frag = which.partition('#')[::2]
|
base, frag = which.partition('#')[::2]
|
||||||
|
base = base.strip('/')
|
||||||
|
if frag.startswith('ref='):
|
||||||
|
ref = frag[4:]
|
||||||
|
which = resolve_ref(ref, lambda x: x)
|
||||||
|
base, frag = which.partition('#')[::2]
|
||||||
|
base = base.strip('/')
|
||||||
if ld:
|
if ld:
|
||||||
base = base or 'index'
|
base = base or 'index'
|
||||||
url = f'file://{ld}/' + quote(base) + '.html'
|
url = f'file://{ld}/' + quote(base) + '.html'
|
||||||
|
|||||||
@ -81,6 +81,7 @@ class TestBuild(BaseTest):
|
|||||||
self.ae(p(), 'file:///docs/index.html')
|
self.ae(p(), 'file:///docs/index.html')
|
||||||
self.ae(p('conf'), 'file:///docs/conf.html')
|
self.ae(p('conf'), 'file:///docs/conf.html')
|
||||||
self.ae(p('kittens/ssh#frag'), 'file:///docs/kittens/ssh.html#frag')
|
self.ae(p('kittens/ssh#frag'), 'file:///docs/kittens/ssh.html#frag')
|
||||||
|
self.ae(p('#ref=confloc'), 'file:///docs/conf.html#confloc')
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user