Compare commits
5 commits
13c34b08e2
...
e960f56b93
| Author | SHA1 | Date | |
|---|---|---|---|
| e960f56b93 | |||
| 3ef552bbe5 | |||
| e84adc4392 | |||
| 84a16ee307 | |||
| 7251504dc4 |
2 changed files with 39 additions and 15 deletions
17
test/test_cli.py
Normal file
17
test/test_cli.py
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
from topen import add_annotation, open_editor
|
||||||
|
|
||||||
|
|
||||||
|
def test_open_editor_escapes_shell():
|
||||||
|
"""Ensure filenames with spaces/metas do not allow shell injection."""
|
||||||
|
with patch("subprocess.run") as run_mock:
|
||||||
|
open_editor(Path("my note$1.txt"), "vim")
|
||||||
|
run_mock.assert_called_once_with(["vim", "my note$1.txt"], check=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_annotation_calls_tasklib():
|
||||||
|
task = Mock()
|
||||||
|
add_annotation(task, "hello")
|
||||||
|
task.add_annotation.assert_called_once_with("hello")
|
||||||
37
topen.py
37
topen.py
|
|
@ -63,11 +63,9 @@ def main(cfg: "TConf | None" = None, io: "_IO | None" = None) -> int:
|
||||||
|
|
||||||
fpath = get_notes_file(uuid, notes_dir=cfg.notes_dir, notes_ext=cfg.notes_ext)
|
fpath = get_notes_file(uuid, notes_dir=cfg.notes_dir, notes_ext=cfg.notes_ext)
|
||||||
|
|
||||||
if not fpath.parent.exists():
|
_ensure_parent_dir(fpath)
|
||||||
fpath.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
io.out(f"Editing note: {fpath}")
|
io.out(f"Editing note: {fpath}")
|
||||||
open_editor(fpath, editor=cfg.notes_editor)
|
open_editor(fpath, editor=cfg.notes_editor, io=io)
|
||||||
|
|
||||||
if fpath.exists():
|
if fpath.exists():
|
||||||
if is_annotation_missing(task, annotation_content=cfg.notes_annot):
|
if is_annotation_missing(task, annotation_content=cfg.notes_annot):
|
||||||
|
|
@ -97,9 +95,13 @@ def get_notes_file(uuid: str, notes_dir: Path, notes_ext: str) -> Path:
|
||||||
return Path(notes_dir).joinpath(f"{uuid}.{notes_ext}")
|
return Path(notes_dir).joinpath(f"{uuid}.{notes_ext}")
|
||||||
|
|
||||||
|
|
||||||
def open_editor(file: Path, editor: str) -> None:
|
def open_editor(file: Path, editor: str, io: "_IO | None" = None) -> None:
|
||||||
"""Opens a file with the chosen editor."""
|
"""Opens a file with the chosen editor."""
|
||||||
_ = subprocess.run(f"{editor} {file}", shell=True)
|
try:
|
||||||
|
_ = subprocess.run([editor, str(file)], check=True)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
if io:
|
||||||
|
io.err("Editor exited with an error, aborting.\n")
|
||||||
|
|
||||||
|
|
||||||
def is_annotation_missing(task: Task, annotation_content: str) -> bool:
|
def is_annotation_missing(task: Task, annotation_content: str) -> bool:
|
||||||
|
|
@ -135,16 +137,21 @@ class Opt:
|
||||||
is_flag: bool = False
|
is_flag: bool = False
|
||||||
|
|
||||||
|
|
||||||
def _real_path(p: Path | str) -> Path:
|
def _expand_path(p: Path | str) -> Path:
|
||||||
return Path(os.path.expandvars(p)).expanduser()
|
return Path(os.path.expandvars(p)).expanduser()
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_parent_dir(file: Path) -> None:
|
||||||
|
if not file.parent.exists():
|
||||||
|
file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
def _determine_default_task_rc() -> Path:
|
def _determine_default_task_rc() -> Path:
|
||||||
if _real_path("~/.taskrc").exists():
|
if _expand_path("~/.taskrc").exists():
|
||||||
return _real_path("~/.taskrc")
|
return _expand_path("~/.taskrc")
|
||||||
if _real_path("$XDG_CONFIG_HOME/task/taskrc").exists():
|
if _expand_path("$XDG_CONFIG_HOME/task/taskrc").exists():
|
||||||
return _real_path("$XDG_CONFIG_HOME/task/taskrc")
|
return _expand_path("$XDG_CONFIG_HOME/task/taskrc")
|
||||||
return _real_path("~/.config/task/taskrc")
|
return _expand_path("~/.config/task/taskrc")
|
||||||
|
|
||||||
|
|
||||||
def _strtobool(val: str) -> bool:
|
def _strtobool(val: str) -> bool:
|
||||||
|
|
@ -258,11 +265,11 @@ class TConf:
|
||||||
"""If set topen will give no feedback on note editing."""
|
"""If set topen will give no feedback on note editing."""
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.task_rc = _real_path(self.task_rc)
|
self.task_rc = _expand_path(self.task_rc)
|
||||||
self.task_data = _real_path(self.task_data)
|
self.task_data = _expand_path(self.task_data)
|
||||||
if self.notes_dir == NON_EXISTENT_PATH:
|
if self.notes_dir == NON_EXISTENT_PATH:
|
||||||
self.notes_dir = self._default_notes_dir()
|
self.notes_dir = self._default_notes_dir()
|
||||||
self.notes_dir = _real_path(self.notes_dir)
|
self.notes_dir = _expand_path(self.notes_dir)
|
||||||
if not self.notes_editor:
|
if not self.notes_editor:
|
||||||
self.notes_editor = (
|
self.notes_editor = (
|
||||||
os.getenv("EDITOR")
|
os.getenv("EDITOR")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue