Merge pull request #30 from karlicoss/updates
Support for dynamic selection/comment formatting
This commit is contained in:
commit
4bc8f01122
|
@ -20,6 +20,13 @@ or your target capture file is just not there, you can selfhost the server part
|
|||
|
||||
That's it! If you're using custom port make sure it's the same as in the extension settings (default is `12212`).
|
||||
|
||||
## Configuration
|
||||
|
||||
[Here](https://github.com/karlicoss/grasp/blob/af24c991579986cec73695daa8318e7831049305/server/org_tools.py#L91-L109) you can find some references for the `--template` syntax.
|
||||
|
||||
If you are looking for more flexible formatting that's not supported by template syntax, see [config.py.example](misc/config.py.example).
|
||||
You can modify it to your liking and pass as `--config` to `grasp_server/setup` scripts.
|
||||
|
||||
# Motivation
|
||||
Why use org-capture? Well, it's hard to explain, maybe some other time... However, if you do know you want to use it instead of/alongside your browser bookmarks, by default
|
||||
you don't have much choice and have to copy everything manually. For an experienced enough org-mode user it's no less than a torture.
|
||||
|
|
20
misc/config.py.example
Normal file
20
misc/config.py.example
Normal file
|
@ -0,0 +1,20 @@
|
|||
from typing import List
|
||||
|
||||
class Config:
|
||||
@staticmethod
|
||||
def format_selection(selection: str) -> List[str]:
|
||||
return [
|
||||
'#+begin_quote',
|
||||
selection,
|
||||
'#+end_quote',
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def format_comment(comment: str) -> List[str]:
|
||||
return [
|
||||
'- comment:'
|
||||
] + [
|
||||
# colon is a quck way to define blocks of code/preformatted stuff: https://orgmode.org/manual/Literal-Examples.html
|
||||
' : ' + s
|
||||
for s in comment.splitlines()
|
||||
]
|
|
@ -6,17 +6,19 @@ import os
|
|||
import logging
|
||||
from pathlib import Path
|
||||
import re
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, Dict, Any
|
||||
|
||||
from org_tools import as_org, empty, DEFAULT_TEMPLATE
|
||||
from org_tools import as_org, empty, DEFAULT_TEMPLATE, Config
|
||||
|
||||
CAPTURE_PATH_VAR = 'GRASP_CAPTURE_PATH'
|
||||
CAPTURE_PATH_VAR = 'GRASP_CAPTURE_PATH'
|
||||
CAPTURE_TEMPLATE_VAR = 'GRASP_CAPTURE_TEMPLATE'
|
||||
CAPTURE_CONFIG_VAR = 'GRASP_CAPTURE_CONFIG'
|
||||
|
||||
|
||||
def get_logger():
|
||||
return logging.getLogger('grasp-server')
|
||||
|
||||
|
||||
def append_org(
|
||||
path: Path,
|
||||
org: str
|
||||
|
@ -32,6 +34,19 @@ def append_org(
|
|||
fo.write(org)
|
||||
|
||||
|
||||
from functools import lru_cache
|
||||
@lru_cache(1)
|
||||
def capture_config() -> Optional[Config]:
|
||||
cvar = os.environ.get(CAPTURE_CONFIG_VAR)
|
||||
if cvar is None:
|
||||
return None
|
||||
|
||||
globs: Dict[str, Any] = {}
|
||||
exec(Path(cvar).read_text(), globs)
|
||||
ConfigClass = globs['Config']
|
||||
return ConfigClass()
|
||||
|
||||
|
||||
def capture(
|
||||
url: str,
|
||||
title,
|
||||
|
@ -48,6 +63,7 @@ def capture(
|
|||
return s
|
||||
capture_path = Path(os.environ[CAPTURE_PATH_VAR]).expanduser()
|
||||
org_template = os.environ[CAPTURE_TEMPLATE_VAR]
|
||||
config = capture_config()
|
||||
logger.info('capturing %s to %s', (url, title, selection, comment, tag_str), capture_path)
|
||||
|
||||
url = safe(url)
|
||||
|
@ -68,6 +84,7 @@ def capture(
|
|||
comment=comment,
|
||||
tags=tags,
|
||||
org_template=org_template,
|
||||
config=config,
|
||||
)
|
||||
append_org(
|
||||
path=capture_path,
|
||||
|
@ -111,13 +128,15 @@ class GraspRequestHandler(BaseHTTPRequestHandler):
|
|||
self.respond_error(message=str(e))
|
||||
|
||||
|
||||
def run(port: str, capture_path: str, template: str):
|
||||
def run(port: str, capture_path: str, template: str, config: Optional[Path]):
|
||||
logger = get_logger()
|
||||
logger.info("Using template %s", template)
|
||||
|
||||
# not sure if there is a simpler way to communicate with the server...
|
||||
os.environ[CAPTURE_PATH_VAR] = capture_path
|
||||
os.environ[CAPTURE_TEMPLATE_VAR] = template
|
||||
if config is not None:
|
||||
os.environ[CAPTURE_CONFIG_VAR] = str(config)
|
||||
httpd = HTTPServer(('', int(port)), GraspRequestHandler)
|
||||
logger.info(f"Starting httpd on port {port}")
|
||||
httpd.serve_forever()
|
||||
|
@ -129,6 +148,8 @@ def setup_parser(p):
|
|||
p.add_argument('--template', type=str, default=DEFAULT_TEMPLATE, help=f"""
|
||||
{as_org.__doc__}
|
||||
""")
|
||||
abspath = lambda p: str(Path(p).absolute())
|
||||
p.add_argument('--config', type=abspath, required=False, help='Optional dynamic config')
|
||||
|
||||
|
||||
def main():
|
||||
|
@ -137,7 +158,7 @@ def main():
|
|||
p = argparse.ArgumentParser('grasp server', formatter_class=lambda prog: argparse.ArgumentDefaultsHelpFormatter(prog, width=100)) # type: ignore
|
||||
setup_parser(p)
|
||||
args = p.parse_args()
|
||||
run(args.port, args.path, args.template)
|
||||
run(args.port, args.path, args.template, args.config)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -4,6 +4,7 @@ from typing import List, Optional
|
|||
|
||||
DEFAULT_TEMPLATE = "* %U %:description %:tags\n%:link\n%:initial\n"
|
||||
|
||||
# TODO reuse inorganic/orgparse??
|
||||
def date2org(t: datetime) -> str:
|
||||
return t.strftime("%Y-%m-%d %a")
|
||||
|
||||
|
@ -18,6 +19,35 @@ def empty(s) -> bool:
|
|||
return s is None or len(s.strip()) == 0
|
||||
|
||||
|
||||
# TODO protocol??
|
||||
# TODO put template in config??
|
||||
class Config:
|
||||
@staticmethod
|
||||
def format_selection(selection: str) -> List[str]:
|
||||
...
|
||||
|
||||
@staticmethod
|
||||
def format_comment(comment: str) -> List[str]:
|
||||
...
|
||||
|
||||
|
||||
class DefaultConfig(Config):
|
||||
@staticmethod
|
||||
def format_selection(selection: str) -> List[str]:
|
||||
return [
|
||||
'Selection:',
|
||||
selection,
|
||||
]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def format_comment(comment: str) -> List[str]:
|
||||
return [
|
||||
'Comment:',
|
||||
comment
|
||||
]
|
||||
|
||||
|
||||
def as_org(
|
||||
url: str,
|
||||
title: str,
|
||||
|
@ -25,6 +55,7 @@ def as_org(
|
|||
comment: str,
|
||||
tags: List[str],
|
||||
org_template: str,
|
||||
config: Optional[Config] = None,
|
||||
):
|
||||
"""
|
||||
Formats captured results according to org template. Supports all sensible (e.g. non-interactive) template expansions from https://orgmode.org/manual/Template-expansion.html#Template-expansion.
|
||||
|
@ -41,19 +72,16 @@ You can look at `test_templates` for some specific examples.
|
|||
|
||||
tags_s = '' if len(tags) == 0 else (':' + ':'.join(tags) + ':')
|
||||
|
||||
if config is None:
|
||||
config = DefaultConfig()
|
||||
|
||||
# TODO tabulate selection and comments?
|
||||
# TODO not sure, maybe add as org quote?
|
||||
parts = []
|
||||
if not empty(selection):
|
||||
parts.extend([
|
||||
'Selection:',
|
||||
selection,
|
||||
])
|
||||
parts.extend(config.format_selection(selection))
|
||||
if not empty(comment):
|
||||
parts.extend([
|
||||
'Comment:',
|
||||
comment
|
||||
])
|
||||
parts.extend(config.format_comment(comment))
|
||||
initial = '\n'.join(parts)
|
||||
|
||||
res = py_template.format(
|
||||
|
|
|
@ -37,8 +37,13 @@ def setup(args):
|
|||
server_bin = Path(__file__).parent.joinpath('grasp_server.py').absolute()
|
||||
|
||||
template = args.template.replace('%', '%%').replace('\n', r'\n') # escape for systemd...
|
||||
template = shlex.quote(template)
|
||||
extra_args = f'--port {args.port} --path {args.path} --template {template}'
|
||||
args = [
|
||||
'--port', args.port,
|
||||
'--path', args.path,
|
||||
'--template', template,
|
||||
*([] if args.config is None else ['--config' , args.config]),
|
||||
]
|
||||
extra_args = ' '.join(map(shlex.quote, args))
|
||||
|
||||
with out.open('w') as fo:
|
||||
fo.write(SYSTEMD_CONFIG.format(
|
||||
|
|
Loading…
Reference in a new issue