时间:2023-07-26 07:12:02 | 来源:网站运营
时间:2023-07-26 07:12:02 来源:网站运营
20.使用org-mode管理浏览器书签:#東方Project あたいってばさいきょ〜ね!!! - なにょち的插画 - pixiv^G 正则得到的结果。 query-replace 有点像,也许可以考虑使用相似方法在 emacs 中实现。 pip install buku 后得到了这样的结果… M-x info 再找 Org,为了写这一部分我花了两天时间把整个文档读了一遍)。当然我更建议读 Org Mode Compact Guide,这个更加简单。 NAMEDESCRIPTION 或是 URL 等固定名字了。这里有篇文章可作参考:bookmarking with org-modeC-c C-x C-w (org-cut-special)来删除一整个标题的内容。 * Search Engine:PROPERTY::Is-Folder: t:END:** Baidu:PROPERTIES::Is-Folder : nil:END:www.baidu.com** google:PROPERTIES::Is-Folder : nil:END:www.google.com...... 不过我不打算使用这种分层分类的方式,如上文所见,我不是太喜欢它,分类层级太多的话查找起来并不方便。我准备直接使用类似表格的格式,也就是只使用同一级标题表示书签,这样实现起来也更加方便。 :ARCHIVE: 的 tag 即可。使用 org-agenda 还可以对归档文件进行方便地搜索。 C-c C-o 即可在默认浏览器中打开链接,但这还是比不上从浏览器中直接点方便。要是能够同步 org 文件和书签栏的话效果应该挺不错的,这就需要我去学习怎么写插件了。使用数据库来与浏览器交互应该会更好,所以等 29 吧(笑)。 [ ] 如果使用 sqlite 就可对数据进行加密(免费版好像不行…,需要使用 SEE 加密工具),这样应该会更加安全一点,也许可以做一个写入和读出数据库的功能,实现 org 文本和数据库的无缝转换[ ] 如果功能足够丰富的话,可以考虑写个 minor-mode[X] 添加下载网页的功能,把值得收藏的网页下载并存储下来url 和 description 可使用 org 的默认格式表示: [[link][description]] 。当在标题上按下 C-c C-o 或单击鼠标时就可在浏览器打开该网页tag tag 直接放在标题后面,使用 : 分隔,举例来说是这样: :a:b:c:PROPERTIES 里面存放链接添加时间等日常无需了解的数据text 放在标题的正文部分,对书签的内容做进一步说明* [[https://baidu.com][百度一下,你就知道]] :search:ATTACH::PROPERTIES::ID: 114514-191981:YYOB-CREATE-TIME: [2022-07-27 Wed 19:36]:YYOB-ID: 1:YYOB-MD5: c4ca4238a0b923820dcc509a6f75849b:END:百度,一个搜索引擎...... 在上面的例子中, :search: 就是 tag, :PROPERTIES: 中的 :ID: 就是 attach 的 ID 值,用来索引保存的文件位置。 :YYOB-CREATE-TIME: 就是创建时间, :END: 后面的文本就是详细描述部分,这部分的内容就随意了。 org-map-entries 遍历文件中的所有标题org-heading-components 获取标题的一些状态,具体内容可 C-h forg-entry-get org-entry-put 获取和设置属性值org-map-tree 遍历所有嵌套的标题yyorg-bookmark ,链接放在本节的最后。首先从设计思路上来说吧。 t- 而不是 yyorg-bookmark- ,emacs 在读取时会自动转换。yyorg-bookmark 里。 #+NAME: startup#+BEGIN_SRC emacs-lisp(your-code-here)#+END_SRC...# Local Variables:# org-confirm-babel-evaluate: nil# eval: (progn (org-babel-goto-named-src-block "startup") (org-babel-execute-src-block) (outline-hide-sublevels 1))# End: 通过将变量使用 setq-local 设置就可设置 buffer 局部变量,这样就不容易引起 buffer 间冲突。同时代码块里也可以包含一些专用于 buffer 的管理函数,它们可以是 yyorg-bookmark 的函数的包装,或是自己定义的管理函数。 yyorg-bookmark-enchant 的命令,使用该命令即可将模板文件附加到当前 buffer 末尾,这样完成了一个 yyorg 书签数据库的建立,完成了对 buffer 的“附魔”(笑)。 symbol-value 来获取。那要如何获取书签文件的 buffer 呢?好在 org-mode 提供了一个模板名与文件对应的关联表 org-capture-templates ,在进行内容捕获时,org-mode 根据它来选择对应的模板,并写入对应的文件。 (yyorg-bookmark--template-filename key) ,根据 org-capture-templates 和模板名获取捕获的目标文件(defun t-get-local-value (key symbol) "get buffer-local value in target file" (let* ((filename (t--template-filename key)) (buf (get-file-buffer filename))) (save-current-buffer (set-buffer buf) (symbol-value symbol))))(defun t-set-local-value (key symbol value) "set buffer-local value in target file" (let* ((filename (t--template-filename key)) (buf (get-file-buffer filename))) (save-current-buffer (set-buffer buf) (set symbol value))))当然这也带来一个问题,代码变长了不少(毕竟是打洞做法……) org-capture-templates 添加/删除的处理。它是我这个包里最重要的全局资源,用来关联模板和书签文件。为了避免出现一些低级错误,比如类型错误,模板错误等,需要对添加过程做一些检查。同时考虑到它的全局性,在添加同名模板时也要检查是否冲突,由用户来决定是否覆盖已存在的同名模板。 yyorg-bookmark-add-template 函数来添加模板,一个简单的例子如下,这是附魔文件里的例子模板: (yyorg-bookmark-add-template :key "l" :desc "Add browser bookmark" :type 'entry :target `(file+headline ,(buffer-file-name) "Bookmarks") :temp "* %c %^g/n:PROPERTIES:/n:YYOB-CREATE-TIME: %T/n:YYOB-ID: %(yyorg-bookmark-control-key-counter /"l/")/n:END:" :props '(:prepend t)))除了添加外也要考虑删除,我还编写了 yyorg-bookmark-remove-template 用于从 minibuffer 中选择并删除模板。 (defun t-remove-template (key) "remove a template from `org-capture-templates'use minibuffer to select a key" (interactive (list (completing-read "key: " (t--template-keys) nil t))) (setq org-capture-templates (cl-delete-if (lambda (x) (string= key (car x))) org-capture-templates))) 再然后就是对属性值的操作,org-mode 提供了一些函数: org-entry-get ,获取某一点所在 HEADLINE 的属性值org-entry-put ,设置某一点所在 HEADLINE 的属性值org-find-entry ,寻找第一个匹配的属性值,返回位置org-find-entry 查找属性位置: (defun t--get-property (pname &optional on-headline) "return string if found, or nil if not" (let ((place (if on-headline (point) (org-find-property pname)))) (if place (org-entry-get place pname) nil)))(defun t--set-property (pname strval &optional on-headline) "set property `pname' if found and return t, or nil if notif on-headline is set and point is on headlinethis function will always success" (let ((place (if on-headline (point) (org-find-property pname)))) (if place (prog1 t (org-entry-put place pname strval)) nil)))另外,由于 org-mode 中属性值都是以字符串保存的,如果要进行数学运算并不方便。我添加了一些计数器操作,可以较方便的对某个属性值进行自增和自减,最终的可用函数如下: (defun t-control-counter (pname op &optional on-headline) "control counter's value'+ is add1, '- is sub1, 'r is reset to 0, 'z is unchangereturn the origin value" (cl-case op ((+) (t-increase-counter pname on-headline)) ((-) (t-decrease-counter pname on-headline)) ((r) (t-reset-counter pname on-headline)) ((z) (t--get-property pname on-headline)) (t (error "unrecognized op %s" op))))最后是对标题属性值的枚举,可以获取所有 HEADLINE 的属性值,这个函数可配合 emacs 的 narrow 功能实现区域枚举。 (defun t-get-all-entries-properties (pnames) "get all entries specific propertyreturn form is ( ((p1 . v1) (p2 . v2) ...) ... )in other words, return value is a nested alistyou can use it with narrow" (let ((pro-list)) (org-map-tree (lambda () (let ((a (org-entry-properties)) (b)) (mapc (lambda (x) (let ((c (assoc x a))) (when c (push c b)))) pnames) (when b (push b pro-list))))) (reverse pro-list)))上面这些函数基本上就是 yyorg-bookmark.el 文件中实现的功能了,接下来我们来到附魔模板的代码编写,来实现一些更加贴近用户的操作。 yyorg-bookmark ,这里不使用 yyorg-bookmark-add-template 函数: (add-to-list 'org-capture-templates `("l" "Add browser bookmark" entry (file+headline ,(buffer-file-name) "Bookmarks") "* %c/n:PROPERTIES:/n:TIME: %T/n:END:" :prepend t)) 上面这段代码的作用是将模板 "l" 添加到 org-capture-templates 中。这里目标选择当前 buffer 对应文件,HEADLINE 选择 Bookmark,属性选择 :prepent t ,这表示将新的项添加到最前。完整版的例子在代码仓库的附魔模板文件中。 M-x org-capture ,然后选中 l ,你可以看到剪切板中的内容被放到了添加项的标题中, TIME 属性值成为了当前时间。接着按下 C-c C-c 完成捕获。动图如下所示: org-capture 后,"Hello world" 出现在了标题位置,这是 %c 的作用,其他的特殊符号可参考官方文档。 org-capture ,更要命的是我从来不用苹果的笔记本电脑。 org-protocol 。 emacsclient file 命令在已启动的 emacs 中打开文件,这样就不会有多个 emacs 实例了,再也不用担心 emacs 启动太慢了(笑)。 (require 'server)(unless (eq (server-running-p) t) (server-start))org-protocol 默认支持三种协议,我们要使用的那一种是 capture ,传递给 emacsclient 的字符串是这样的一个格式: emacsclient "org-protocol://capture?template=X&url=URL&title=TITLE&body=BODY" 调用 emacsclient 后, org-capture 会使用模板 X 来处理捕获内容,并完成捕获。可以看到上面的内容包括三个部分,分别是 url,标题和内容,使用文档中的对应的特殊符号即可在 org-capture 模板中获取这些字符串。通过设置一些选项, org-capture 可以不需要 C-c C-c 确认而直接完成捕获过程,这样就可以一键捕获了。 REGEDIT4; see https://orgmode.org/worg/org-contrib/org-protocol.html; and https://github.com/sprig/org-capture-extension[HKEY_CLASSES_ROOT/org-protocol]@="URL:Org Protocol""URL Protocol"=""[HKEY_CLASSES_ROOT/org-protocol/shell][HKEY_CLASSES_ROOT/org-protocol/shell/open][HKEY_CLASSES_ROOT/org-protocol/shell/open/command]; use you own path to emacsclientw.exe@="/"path//to//your//emacs//bin//emacsclientw.exe" /"%1/""具体原理可以参考 “有个网站想打开此应用”原理是什么?,这里直接摘过来了: 作者:Hawaii在添加相应的注册表项后,当你在浏览器地址栏中输入类似
链接:https://www.zhihu.com/question/410173377/answer/1366638756
来源:本站
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1.浏览器解析URL,得到协议部分thunder://
2.浏览器尝试在已知的协议列表中匹配thunder协议
3.thunder不是已知协议,浏览器转而在注册表中查找thunder协议的注册信息,也即HKEY_CLASSES_ROOT/thunder这个键
4.浏览器使用这个键下的Shell/Open/command子键的值作为运行此协议的程序路径,并将URL的路径部分作为程序的参数
5.浏览器弹出提示框“有个网站想打开此应用”,询问用户是否要执行此协议关联的程序。
org-protocol://capture?template=l&url=baidu.com&title=百度一下你就知道&body=hello 的 url 时,浏览器就会提示你是否运行 emacsclient,点击运行即可执行捕获动作。 location.href = 'org-protocol://capture?template=' + key + '&url=' + encodeURIComponent(location.href) + '&title=' + encodeURIComponent(document.title) + '&body=' + encodeURIComponent(window.getSelection());// use this for bookmarkjavascript:location.href='org-protocol://capture?template='+'yyobp'+'&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)+'&body='+encodeURIComponent(window.getSelection());在一些浏览器中你可以将那一长条代码放到书签地址中,然后点击书签即可实现捕获。我在 firefox 和 edge 上进行了尝试,firefox 可行但 edge 不可行。edge 不允许从书签处执行 JS 代码。使用书签不能适用于所有浏览器。下图是 firefox 的编辑书签对话框: org-capture 的插件,这里是源代码及文档。按照它的说明配置好 emacs 后,点击浏览器插件的那个马头(还是独角兽?)就可以一键保存了。很可惜这个插件在 edge 上并没有。 // ==UserScript==// @name yyob-add-bookmark// @namespace http://tampermonkey.net/// @version 0.1// @description use org-protocol and tm-script to add bookmark// @author include-yy// @match *://*/*// @grant unsafeWindow// @grant GM_registerMenuCommand// ==/UserScript==(function() { 'use strict'; // Your code here... // all templates // [key, description, accesskey] // comment or uncomment to add/remove item let all = [ ['yyobp', 'Add Bookmark', 'a'], ['L', 'add bk 2', 'p'] ]; let i = 0; // https://stackoverflow.com/questions/25750183/how-to-create-a-toolbar-button-for-a-chrome-tampermonkey-user-script // how to add MenuCommand for (i = 0; i < all.length; i++) { let name = all[i][0]; let desc = all[i][1]; let hotkey = all[i][2]; GM_registerMenuCommand(desc, function() { main(name); }, hotkey); } // https://github.com/toure00/org-capture-tag-bookmark // how to capture link and description function main (key) { location.href = 'org-protocol://capture?template=' + key + '&url=' + encodeURIComponent(location.href) + '&title=' + encodeURIComponent(document.title) + '&body=' + encodeURIComponent(window.getSelection()); } // my original thought was to use radio/checkbox dialog to add or remove template to use // but I found it easier to just add/remove a list in a list variable :p // if you want to do like this, you can refer to // https://stackoverflow.com/questions/11668111/how-do-i-pop-up-a-custom-form-dialog-in-a-greasemonkey-script // and https://github.com/toure00/org-capture-tag-bookmark // if you want to use jQuery, just paste blow line to the ==userscript== block // @require https://code.jquery.com/jquery-2.1.4.min.js})();https://www.zhihu.com/video/1537991207703166976下面是上面演示中使用的捕获模板, template 部分看着非常别扭,下面会解释原因: (yyorg-bookmark-add-template :key "yyobp" :desc "Add browser bookmark" :type 'entry :target `(file+headline ,(buffer-file-name) "Bookmarks") :temp "* [[%:link][%:description]] %(yyorg-bookmark-add-repeat-tag (md5 /"%:link/") (yyorg-bookmark-get-local-value /"yyobp/" 'yyob-hashtable) 'gethash)/n:PROPERTIES:/n:YYOB-ID: %(if (string= (yyorg-bookmark-add-repeat-tag (md5 /"%:link/") (yyorg-bookmark-get-local-value /"yyobp/" 'yyob-hashtable) 'gethash) /"/") (progn (puthash (md5 /"%:link/") (yyorg-bookmark-control-key-counter /"yyobp/" 'z) (yyorg-bookmark-get-local-value /"yyobp/" 'yyob-hashtable)) (yyorg-bookmark-control-key-counter /"yyobp/")) (gethash (md5 /"%:link/") (yyorg-bookmark-get-local-value /"yyobp/" 'yyob-hashtable)))/n:YYOB-CREATE-TIME: %T/n:YYOB-MD5: %(md5 /"%:link/")/n:END:%(if (string= /"/" /"%i/") /"/" /"/n%i/")" :props '(:prepend t :immediate-finish t :jump-to-captured t))) 这一部分我参考的资料有很多: org-cut-subtree ( C-c C-x C-w )来删除整一个书签的内容。 C-c k 来删除书签,使用 C-c i 来添加书签(信息)。与普通的文本操作不同,这两个操作会修改一些管理信息。 :repeat: tag。 C-c k 上。与之相反, C-c i 的作用是将项的 信息 添加到哈希表中,若信息已存在则不进行操作。 C-c k 删除了某书签,但是我们又想让它恢复到没有删除之前的状态,那可以 C-/ (undo)然后使用 C-c i 将书签信息重新添加到哈希表中。 C-c r 快捷键,它根据当前的书签项来刷新哈希表,你可以多次删除多个书签后直接使用它,而不需要使用多次 C-c k 。 %^g ),添加 tag 可将光标移至 headline 处并按下 C-c C-c ,然后 emacs 会提提供一些已存在的 tag 供你选择。这些没什么好说的,下面参考官方文档简单提一下嵌套 tag 的写法。 # 注意空格,所有的空格都是必要的#+TAGS: [ GTD : Control Persp ]#+TAGS: [ Control : Context Task ]#+TAGS: [ Persp : Vision Goal AOF Project ]C-c C-a a 添加文件后 org-mode 会给标题分配一个唯一的 ID,以及和 ID 关联的文件夹,附加的文件默认会复制到该文件夹内。使用 C-c C-a o 可打开文件夹内某一文件,使用 C-c C-a f 可在 emacs 中打开该文件目录。 (defun t-get-url-from-link (str) "get link from [[link][description]]" (cl-assert (string= (substring str 0 2) "[[")) (let ((i 0)) (while (and (not (= (aref str i) ?/])) (< i (length str))) (cl-incf i)) (if (= i (length str)) (error "link not found") (substring str 2 i))));; https://stackoverflow.com/questions/13505113/how-to-open-the-native-cmd-exe-window-in-emacs;; https://www.tecmint.com/wget-download-file-to-specific-directory/;; https://www.anycodings.com/1questions/2463613/is-it-possible-for-wget-to-flatten-the-result-directories(defun t-attach-use-wget (link) "-E -H -k -K -p -nd -e robots=off -P target-directory used only on windows just to modify cmd to bash and something else to adapt to linux or use advice" (let* ((dir-path (org-attach-dir-get-create)) (wget-exe (or t-wget-path "wget"))) (let ((proc (start-process "yyob-wget" nil "cmd.exe" "/C" "start" "cmd.exe" "/K" wget-exe "-E" "-k" "-K" "-p" "-nd" "-e" "robots=off" link "-P" dir-path))) (set-process-query-on-exit-flag proc nil)))) 在 windows 上使用需要配置 yyorg-wget-path 为 wget 的绝对路径,不过由于我现在懒得弄 linux,我也没有写使用 bash 的 linux 版本,我将下载键绑定在了 C-c u 上。org-attach 提供的默认下载功能太弱,不建议使用。 C-c [ 把 buffer 加入到它的搜索列表中,如果想要移除某 buffer 就在该 buffer 中按下 C-c ] 。使用 M-x org-agenda 即可进入搜索选择界面,它提供了非常多的选择,org-mode 建议将该命令绑定到 C-c a 上: (global-set-key (bkd "C-c a") 'org-agenda) 我在书签文件中添加了局部快捷键 C-c m ,它可以直接清空 org-agenda 使用的文件表,这样就不用一个一个 C-c ] 了。 t 列出所有的 TODO 项, T 列出带有特殊 TODO 标志的项m 搜索 tag/prop/todo, M 只对 TODO 项进行搜索s 关键词搜索, S 只对 TODO 项进行搜索/ 使用多 buffer occur 进行搜索? 找到带有 :FLAGGED: tag 的项# 列出所有阻塞的项目yyorg-bookmark 的全部功能,感兴趣的话可以自己动手,在附魔模板的基础上添加自己想要的功能。 关键词:书签,浏览,管理,使用