Compare commits
7 commits
e960f56b93
...
04d21c61fa
| Author | SHA1 | Date | |
|---|---|---|---|
| 04d21c61fa | |||
| 28c551e157 | |||
| 762b4a288f | |||
| 3f10b429a2 | |||
| 49bd1292fa | |||
| 1ea149c1de | |||
| e50fc9444a |
7 changed files with 263 additions and 129 deletions
27
test/conftest.py
Normal file
27
test/conftest.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from topen import OPTIONS
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fake_id(monkeypatch):
|
||||||
|
monkeypatch.setattr("sys.argv", ["topen", "0"])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def isolate_env(monkeypatch):
|
||||||
|
# delete all existing env vars that could interfere
|
||||||
|
monkeypatch.delenv("EDITOR", raising=False)
|
||||||
|
monkeypatch.delenv("VISUAL", raising=False)
|
||||||
|
for opt in OPTIONS.values():
|
||||||
|
if opt.env:
|
||||||
|
monkeypatch.delenv(opt.env, raising=False)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fake_rc(tmp_path: Path, monkeypatch):
|
||||||
|
rc = tmp_path / "test.taskrc"
|
||||||
|
monkeypatch.setattr(OPTIONS["task_rc"], "default", rc)
|
||||||
|
return rc
|
||||||
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")
|
||||||
|
|
@ -1,118 +1,11 @@
|
||||||
|
# pyright: reportUnusedImport=false, reportUnusedParameter=false
|
||||||
|
# ruff: noqa: F401, F811
|
||||||
|
# ^ Turn off for implicit pytest fixture import
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from topen import OPTIONS, TConf, parse_cli, parse_env, parse_rc
|
from topen import TConf, build_config
|
||||||
|
|
||||||
|
|
||||||
class TestCli:
|
|
||||||
def test_cli_minimum_id(self, monkeypatch):
|
|
||||||
monkeypatch.setattr("sys.argv", ["topen", "42"])
|
|
||||||
assert parse_cli() == {"task_id": "42"}
|
|
||||||
|
|
||||||
def test_cli_options(self, monkeypatch):
|
|
||||||
monkeypatch.setattr(
|
|
||||||
"sys.argv",
|
|
||||||
[
|
|
||||||
"topen",
|
|
||||||
"123",
|
|
||||||
"--extension",
|
|
||||||
"txt",
|
|
||||||
"--editor",
|
|
||||||
"vim",
|
|
||||||
"--quiet",
|
|
||||||
"True",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
assert parse_cli() == {
|
|
||||||
"task_id": "123",
|
|
||||||
"notes_ext": "txt",
|
|
||||||
"notes_editor": "vim",
|
|
||||||
"notes_quiet": True,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def isolate_env(monkeypatch):
|
|
||||||
# delete all existing env vars that could interfere
|
|
||||||
monkeypatch.delenv("EDITOR", raising=False)
|
|
||||||
monkeypatch.delenv("VISUAL", raising=False)
|
|
||||||
for opt in OPTIONS.values():
|
|
||||||
if opt.env:
|
|
||||||
monkeypatch.delenv(opt.env, raising=False)
|
|
||||||
|
|
||||||
|
|
||||||
class TestEnv:
|
|
||||||
def test_env_notes_ext(self, isolate_env, monkeypatch):
|
|
||||||
monkeypatch.setenv("TOPEN_NOTES_DIR", "/blablubb")
|
|
||||||
monkeypatch.setenv("TOPEN_NOTES_EXT", "rst")
|
|
||||||
monkeypatch.setenv("TOPEN_NOTES_ANNOT", "qmd")
|
|
||||||
monkeypatch.setenv("TOPEN_NOTES_EDITOR", "vim")
|
|
||||||
monkeypatch.setenv("TOPEN_NOTES_QUIET", "true")
|
|
||||||
env = parse_env()
|
|
||||||
assert env["notes_dir"] == Path("/blablubb")
|
|
||||||
assert env["notes_ext"] == "rst"
|
|
||||||
assert env["notes_annot"] == "qmd"
|
|
||||||
assert env["notes_editor"] == "vim"
|
|
||||||
assert env["notes_quiet"] is True
|
|
||||||
|
|
||||||
def test_env_task_rc(self, isolate_env, monkeypatch):
|
|
||||||
monkeypatch.setenv("TASKRC", "/a/dir/that/dont/exist/file")
|
|
||||||
monkeypatch.setenv("TASKDATA", "~/somewhere/tasks")
|
|
||||||
env = parse_env()
|
|
||||||
assert env["task_rc"] == Path("/a/dir/that/dont/exist/file")
|
|
||||||
assert env["task_data"] == Path("~/somewhere/tasks")
|
|
||||||
|
|
||||||
def test_env_parses_boolean_true(self, isolate_env, monkeypatch):
|
|
||||||
monkeypatch.setenv("TOPEN_NOTES_QUIET", "true")
|
|
||||||
env = parse_env()
|
|
||||||
assert env["notes_quiet"] is True
|
|
||||||
|
|
||||||
def test_env_parses_boolean_false(self, isolate_env, monkeypatch):
|
|
||||||
monkeypatch.setenv("TOPEN_NOTES_QUIET", "false")
|
|
||||||
env = parse_env()
|
|
||||||
assert env["notes_quiet"] is False
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def fake_rc(tmp_path: Path, monkeypatch):
|
|
||||||
rc = tmp_path / "test.taskrc"
|
|
||||||
monkeypatch.setattr(OPTIONS["task_rc"], "default", rc)
|
|
||||||
return rc
|
|
||||||
|
|
||||||
|
|
||||||
class TestRcFile:
|
|
||||||
def test_taskrc_parsing(self, fake_rc):
|
|
||||||
fake_rc.write_text("""
|
|
||||||
data.location=~/.taskies
|
|
||||||
notes.dir=/there
|
|
||||||
notes.ext=yaml
|
|
||||||
notes.annot=Boo!
|
|
||||||
notes.editor=micro
|
|
||||||
notes.quiet=true
|
|
||||||
""")
|
|
||||||
rc_cfg = parse_rc(fake_rc)
|
|
||||||
assert rc_cfg["task_data"] == Path("~/.taskies")
|
|
||||||
assert rc_cfg["notes_dir"] == Path("/there")
|
|
||||||
assert rc_cfg["notes_ext"] == "yaml"
|
|
||||||
assert rc_cfg["notes_annot"] == "Boo!"
|
|
||||||
assert rc_cfg["notes_editor"] == "micro"
|
|
||||||
assert rc_cfg["notes_quiet"] is True
|
|
||||||
|
|
||||||
def test_taskrc_parses_boolean_true(self, fake_rc):
|
|
||||||
fake_rc.write_text("""
|
|
||||||
notes.quiet=true
|
|
||||||
""")
|
|
||||||
rc_cfg = parse_rc(fake_rc)
|
|
||||||
assert rc_cfg["notes_quiet"] is True
|
|
||||||
|
|
||||||
def test_taskrc_parses_boolean_false(self, fake_rc):
|
|
||||||
fake_rc.write_text("""
|
|
||||||
notes.quiet=false
|
|
||||||
""")
|
|
||||||
rc_cfg = parse_rc(fake_rc)
|
|
||||||
assert rc_cfg["notes_quiet"] is False
|
|
||||||
|
|
||||||
|
|
||||||
class TestTConf:
|
class TestTConf:
|
||||||
def test_paths_are_expanded(self):
|
def test_paths_are_expanded(self):
|
||||||
|
|
@ -140,7 +33,68 @@ class TestTConf:
|
||||||
({"VISUAL": "nvim", "EDITOR": "notepad"}, "notepad"),
|
({"VISUAL": "nvim", "EDITOR": "notepad"}, "notepad"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_editor_env_resolution(isolate_env, monkeypatch, env, expected):
|
def test_editor_env_resolution(self, isolate_env, monkeypatch, env, expected):
|
||||||
for k, v in env.items():
|
for k, v in env.items():
|
||||||
monkeypatch.setenv(k, v)
|
monkeypatch.setenv(k, v)
|
||||||
assert TConf(0).notes_editor == expected
|
assert TConf(0).notes_editor == expected
|
||||||
|
|
||||||
|
|
||||||
|
class TestBuildConfigPrecedence:
|
||||||
|
"""
|
||||||
|
All tests exercise the same key (notes_ext) to keep the assertions short.
|
||||||
|
Each source sets a different value so we can be sure the right one wins.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_defaults_only(self, fake_rc, monkeypatch, isolate_env, fake_id):
|
||||||
|
cfg = build_config()
|
||||||
|
assert cfg.notes_ext == "md"
|
||||||
|
|
||||||
|
def test_taskrc_overrides_defaults(
|
||||||
|
self, fake_rc, monkeypatch, isolate_env, fake_id
|
||||||
|
):
|
||||||
|
fake_rc.write_text("notes.ext=from-rc\n")
|
||||||
|
cfg = build_config()
|
||||||
|
assert cfg.notes_ext == "from-rc"
|
||||||
|
|
||||||
|
def test_env_overrides_taskrc(self, fake_rc, monkeypatch, isolate_env, fake_id):
|
||||||
|
fake_rc.write_text("notes.ext=from-rc\n")
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_EXT", "from-env")
|
||||||
|
cfg = build_config()
|
||||||
|
assert cfg.notes_ext == "from-env"
|
||||||
|
|
||||||
|
def test_cli_overrides_env(self, fake_rc, monkeypatch, isolate_env):
|
||||||
|
fake_rc.write_text("notes.ext=from-rc\n")
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_EXT", "from-env")
|
||||||
|
monkeypatch.setattr("sys.argv", ["topen", "0", "--extension", "from-cli"])
|
||||||
|
cfg = build_config()
|
||||||
|
assert cfg.notes_ext == "from-cli"
|
||||||
|
|
||||||
|
def test_cli_overrides_everything(self, fake_rc, monkeypatch, isolate_env):
|
||||||
|
fake_rc.write_text("notes.ext=from-rc\nnotes.dir=/rc-dir\nnotes.editor=joe")
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_EXT", "from-env")
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_DIR", "/env-dir")
|
||||||
|
monkeypatch.setenv("EDITOR", "emacs")
|
||||||
|
# CLI wins
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"sys.argv",
|
||||||
|
[
|
||||||
|
"topen",
|
||||||
|
"0",
|
||||||
|
"--extension",
|
||||||
|
"cli-ext",
|
||||||
|
"--notes-dir",
|
||||||
|
"cli-dir",
|
||||||
|
"--editor",
|
||||||
|
"helix",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
cfg = build_config()
|
||||||
|
assert cfg.notes_ext == "cli-ext"
|
||||||
|
assert cfg.notes_dir == Path("cli-dir")
|
||||||
|
assert cfg.notes_editor == "helix"
|
||||||
|
|
||||||
|
# sanity check that the task-id coming from CLI is preserved
|
||||||
|
def test_cli_supplies_task_id(self, fake_rc, monkeypatch, isolate_env):
|
||||||
|
monkeypatch.setattr("sys.argv", ["topen", "42"])
|
||||||
|
cfg = build_config()
|
||||||
|
assert cfg.task_id == "42"
|
||||||
|
|
|
||||||
48
test/test_parse_cli.py
Normal file
48
test/test_parse_cli.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from topen import parse_cli
|
||||||
|
|
||||||
|
|
||||||
|
class TestCli:
|
||||||
|
def test_cli_minimum_id(self, monkeypatch):
|
||||||
|
monkeypatch.setattr("sys.argv", ["topen", "42"])
|
||||||
|
assert parse_cli() == {"task_id": "42"}
|
||||||
|
|
||||||
|
def test_cli_options(self, monkeypatch):
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"sys.argv",
|
||||||
|
[
|
||||||
|
"topen",
|
||||||
|
"123",
|
||||||
|
"--extension",
|
||||||
|
"txt",
|
||||||
|
"--editor",
|
||||||
|
"vim",
|
||||||
|
"--annotation",
|
||||||
|
"HERENOTE",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert parse_cli() == {
|
||||||
|
"task_id": "123",
|
||||||
|
"notes_ext": "txt",
|
||||||
|
"notes_editor": "vim",
|
||||||
|
"notes_annot": "HERENOTE",
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_cli_notes_quiet_is_flag(self, monkeypatch):
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"sys.argv",
|
||||||
|
[
|
||||||
|
"topen",
|
||||||
|
"123",
|
||||||
|
"--quiet",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert parse_cli()["notes_quiet"] is True
|
||||||
|
|
||||||
|
def test_cli_parses_paths(self, monkeypatch):
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"sys.argv",
|
||||||
|
["topen", "123", "--notes-dir", "/somewhere/else"],
|
||||||
|
)
|
||||||
|
assert parse_cli()["notes_dir"] == Path("/somewhere/else")
|
||||||
35
test/test_parse_env.py
Normal file
35
test/test_parse_env.py
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from topen import parse_env
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnv:
|
||||||
|
def test_env_notes_ext(self, isolate_env, monkeypatch):
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_DIR", "/blablubb")
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_EXT", "rst")
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_ANNOT", "qmd")
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_EDITOR", "vim")
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_QUIET", "true")
|
||||||
|
env = parse_env()
|
||||||
|
assert env["notes_dir"] == Path("/blablubb")
|
||||||
|
assert env["notes_ext"] == "rst"
|
||||||
|
assert env["notes_annot"] == "qmd"
|
||||||
|
assert env["notes_editor"] == "vim"
|
||||||
|
assert env["notes_quiet"] is True
|
||||||
|
|
||||||
|
def test_env_task_rc(self, isolate_env, monkeypatch):
|
||||||
|
monkeypatch.setenv("TASKRC", "/a/dir/that/dont/exist/file")
|
||||||
|
monkeypatch.setenv("TASKDATA", "~/somewhere/tasks")
|
||||||
|
env = parse_env()
|
||||||
|
assert env["task_rc"] == Path("/a/dir/that/dont/exist/file")
|
||||||
|
assert env["task_data"] == Path("~/somewhere/tasks")
|
||||||
|
|
||||||
|
def test_env_parses_boolean_true(self, isolate_env, monkeypatch):
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_QUIET", "true")
|
||||||
|
env = parse_env()
|
||||||
|
assert env["notes_quiet"] is True
|
||||||
|
|
||||||
|
def test_env_parses_boolean_false(self, isolate_env, monkeypatch):
|
||||||
|
monkeypatch.setenv("TOPEN_NOTES_QUIET", "false")
|
||||||
|
env = parse_env()
|
||||||
|
assert env["notes_quiet"] is False
|
||||||
36
test/test_parse_rc.py
Normal file
36
test/test_parse_rc.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from topen import parse_rc
|
||||||
|
|
||||||
|
|
||||||
|
class TestRcFile:
|
||||||
|
def test_taskrc_parsing(self, fake_rc):
|
||||||
|
fake_rc.write_text("""
|
||||||
|
data.location=~/.taskies
|
||||||
|
notes.dir=/there
|
||||||
|
notes.ext=yaml
|
||||||
|
notes.annot=Boo!
|
||||||
|
notes.editor=micro
|
||||||
|
notes.quiet=true
|
||||||
|
""")
|
||||||
|
rc_cfg = parse_rc(fake_rc)
|
||||||
|
assert rc_cfg["task_data"] == Path("~/.taskies")
|
||||||
|
assert rc_cfg["notes_dir"] == Path("/there")
|
||||||
|
assert rc_cfg["notes_ext"] == "yaml"
|
||||||
|
assert rc_cfg["notes_annot"] == "Boo!"
|
||||||
|
assert rc_cfg["notes_editor"] == "micro"
|
||||||
|
assert rc_cfg["notes_quiet"] is True
|
||||||
|
|
||||||
|
def test_taskrc_parses_boolean_true(self, fake_rc):
|
||||||
|
fake_rc.write_text("""
|
||||||
|
notes.quiet=true
|
||||||
|
""")
|
||||||
|
rc_cfg = parse_rc(fake_rc)
|
||||||
|
assert rc_cfg["notes_quiet"] is True
|
||||||
|
|
||||||
|
def test_taskrc_parses_boolean_false(self, fake_rc):
|
||||||
|
fake_rc.write_text("""
|
||||||
|
notes.quiet=false
|
||||||
|
""")
|
||||||
|
rc_cfg = parse_rc(fake_rc)
|
||||||
|
assert rc_cfg["notes_quiet"] is False
|
||||||
51
topen.py
51
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:
|
||||||
|
|
@ -132,19 +134,24 @@ class Opt:
|
||||||
metavar: str | None = None
|
metavar: str | None = None
|
||||||
cast: type | Callable = str
|
cast: type | Callable = str
|
||||||
help_text: str = ""
|
help_text: str = ""
|
||||||
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:
|
||||||
|
|
@ -224,7 +231,8 @@ OPTIONS: dict[str, Opt] = {
|
||||||
"notes.quiet",
|
"notes.quiet",
|
||||||
default=False,
|
default=False,
|
||||||
cast=_strtobool,
|
cast=_strtobool,
|
||||||
help_text="Silence any verbose displayed information",
|
help_text="Silence any verbosely displayed information",
|
||||||
|
is_flag=True,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,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")
|
||||||
|
|
@ -321,6 +329,15 @@ you view the task.
|
||||||
for key, opt in OPTIONS.items():
|
for key, opt in OPTIONS.items():
|
||||||
if opt.cli is None:
|
if opt.cli is None:
|
||||||
continue
|
continue
|
||||||
|
if opt.is_flag:
|
||||||
|
parser.add_argument(
|
||||||
|
*opt.cli,
|
||||||
|
dest=key,
|
||||||
|
help=opt.help_text,
|
||||||
|
default=None,
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
continue
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
*opt.cli,
|
*opt.cli,
|
||||||
dest=key,
|
dest=key,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue