-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinbox.py
More file actions
68 lines (55 loc) · 4.1 KB
/
Copy pathinbox.py
File metadata and controls
68 lines (55 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
"""Голосовой инбокс: диктовка дописывается в конец файла.
Мысль на ходу диктовать некуда: сначала надо найти окно, встать в поле, и к
этому моменту мысли уже нет. Инбокс убирает оба шага - нажал, сказал, запись в
файле. Файл обычный: .md для Obsidian, .txt для блокнота, - его видно сразу и
без нас, и он останется читаемым, даже если программу удалить.
Отдельным модулем, а не методом в app.py, по той же причине, что notes.py:
здесь теряются данные человека, и проверять это надо тестом, которому не нужны
ни Qt, ни микрофон, ни хоткеи.
Формат записи - пустая строка, «- 21:40», текст:
- 21:40
Купить билеты до пятницы
- 21:44
Позвонить в сервис
Дефис и время - чтобы в Obsidian это читалось списком, а глазами - дневником.
Дата в строке не стоит намеренно: инбокс разбирают в тот же день, а дату видно
по файлу. Кому нужна дата, тот заводит по файлу на день.
"""
import os
import time
def _stamp(when=None) -> str:
return time.strftime("%H:%M", when or time.localtime())
def append(path: str, text: str, when=None) -> bool:
"""Дописать запись в конец файла. False - не вышло, текст не сохранён.
False здесь не ошибка, а развилка: вызывающий отдаёт текст в буфер обмена
(app._to_clipboard) и говорит об этом на пилюле. Поэтому мы не бросаем ни
на занятом файле, ни на пути в несуществующей папке - просто честно
отвечаем «нет», и диктовка не пропадает.
Папку не создаём. Путь с опечаткой - это опечатка, а не просьба развести
дерево каталогов; создав его молча, мы бы прятали ошибку человека, и он
искал бы свои заметки в папке, которой не собирался заводить.
"""
text = (text or "").strip()
path = os.path.expanduser(str(path or "").strip())
if not path or not text:
return False
try:
# Отступ считаем по тому, чем кончился файл. Своё «\n» в начале записи
# даёт пустую строку только если файл уже кончается переводом строки;
# иначе оно просто закроет чужую последнюю строку, и запись прилипнет
# к ней вплотную. Пустого файла это не касается - лишний перевод строки
# в начале выглядит как забытая кем-то пустая строка.
head = ""
size = os.path.getsize(path) if os.path.exists(path) else 0
if size:
with open(path, "rb") as f:
f.seek(-1, os.SEEK_END)
head = "\n" if f.read(1) == b"\n" else "\n\n"
# newline="\n" обязателен: в текстовом режиме Windows сама превратила бы
# наш перевод строки в CRLF, и файл стал бы смесью двух переносов -
# своих и чужих, если его правили ещё чем-то.
with open(path, "a", encoding="utf-8", newline="\n") as f:
f.write(f"{head}- {_stamp(when)}\n{text}\n")
return True
except OSError:
return False