From mboxrd@z Thu Jan 1 00:00:00 1970 From: John Kitchin Subject: Draft of links-9.0 Date: Tue, 05 Jul 2016 10:50:20 -0400 Message-ID: Mime-Version: 1.0 Content-Type: text/plain Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:49109) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bKRgC-0002ut-ON for emacs-orgmode@gnu.org; Tue, 05 Jul 2016 10:50:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bKRg8-00005w-J8 for emacs-orgmode@gnu.org; Tue, 05 Jul 2016 10:50:27 -0400 Received: from mail-qk0-x22e.google.com ([2607:f8b0:400d:c09::22e]:34907) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bKRg8-00005q-E8 for emacs-orgmode@gnu.org; Tue, 05 Jul 2016 10:50:24 -0400 Received: by mail-qk0-x22e.google.com with SMTP id s126so6006494qkh.2 for ; Tue, 05 Jul 2016 07:50:24 -0700 (PDT) Received: from Johns-MacBook-Air.local (KITCHIN-TIMEMACHINE.CHEME.CMU.EDU. [128.2.54.215]) by smtp.gmail.com with ESMTPSA id r47sm1487522qtc.36.2016.07.05.07.50.22 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 05 Jul 2016 07:50:22 -0700 (PDT) List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: "Emacs-orgmode" To: "emacs-orgmode@gnu.org" Hi all, I have completed a draft of links-9.0 (https://github.com/jkitchin/org-mode/tree/link-9.0). This centralizes almost all link properties into a variable `org-link-parameters' and makes it possible to customize almost everything in the link. This branch passes all the tests except these: 2 unexpected results: FAILED ob-shell/bash-uses-assoc-arrays FAILED test-ob/indented-cached-org-bracket-link which also fail for me on master. There are about 27 commits from this branch to master I think. I didn't make patches for all of them yet, since that seemed like a bunch of them. This branch doesn't fix anything in contrib yet (except the manual). I am pretty sure all the previous link behavior has been preserved, and a lot of new things are possible with this. Below are some example uses. Let me know what you think! * Example links ** A basic link Predefined links work the same as before. A doi:10.1021 link and [[doi:10.1021][bracketed version]]. This should look and act like it did before. #+BEGIN_SRC emacs-lisp (org-add-link-type "test" nil nil) #+END_SRC #+RESULTS: : Created test link. A test:link and [[test:link][bracketed form]] ** A colored link with a static tooltip. #+BEGIN_SRC emacs-lisp (org-add-link-type "red" ;; follow (lambda (path) (message "You clicked me.")) ;; export (lambda (path desc backend) (cond ((eq 'html backend) (format "%s" (or desc path))))) :face '(:foreground "red") :help-echo "Click me for a message.") #+END_SRC #+RESULTS: : Created red link. A red:link that is colored red. In bracketed form: A [[red:link][link with a description]]. ** A link with defface #+BEGIN_SRC emacs-lisp (defface org-link-green '((t (:inherit org-link :foreground "green"))) "A green link.") (org-add-link-type "green" ;; follow (lambda (path) (message "You clicked me.")) ;; export (lambda (path desc backend) (cond ((eq 'html backend) (format "%s" (or desc path))))) :face 'org-link-green :help-echo "Click me for a message.") #+END_SRC #+RESULTS: : Created green link. A green:link works. ** A colored link with a static tooltip and no folding. This link will be shown in full unfolded form even when other links are folded in descriptive format. #+BEGIN_SRC emacs-lisp (org-add-link-type "red-full" ;; follow (lambda (path) (message "You clicked me.")) ;; export (lambda (path desc backend) (cond ((eq 'html backend) (format "%s" (or desc path))))) :face '(:foreground "red") :display 'full :help-echo "Click me for a message.") #+END_SRC #+RESULTS: : Created red-full link. A red-full:link that is colored red. In bracketed form: A [[red-full:link][link with a description]]. [[doi:test][bracketed doi]] ** A dynamic tooltip You can make tooltips dynamic. The function must take these arguments (window object position), and construct the tooltip from that information. Here is one way. #+BEGIN_SRC emacs-lisp (defun redd-tip (window object position) (save-excursion (goto-char position) (goto-char (org-element-property :begin (org-element-context))) (cond ((looking-at org-plain-link-re) (format "Looking at %s with mouse at %s" (match-string 0) position)) ((looking-at org-bracket-link-regexp) (format "Looking at %s in a bracketed link with mouse at %s" (match-string 0) position)) (t "No match")))) (org-add-link-type "redd" nil nil :face '(:underline t) :help-echo 'redd-tip) #+END_SRC #+RESULTS: : Created redd link. A link with a dynamic tooltip: redd:link or this one redd:another-link [[redd:test][bracketed redd]] ** A link with a modified keymap This is not new behavior, you could always add new key bindings to the org-mouse-map. You probably don't want to define characters here, since it would lead to editing problems. Note this affects all links now, however. #+BEGIN_SRC emacs-lisp (defun s-click () (interactive) (message-box "You always wanted this right ;)")) (org-defkey org-mouse-map [s-mouse-1] 's-click) (org-defkey org-mouse-map [C-up] (lambda () (interactive) (message-box "Got C-up"))) (org-add-link-type "mouse-1" nil nil) #+END_SRC #+RESULTS: : Created mouse-1 link. mouse-1:test ** a link with a new keymap. To get a special keymap, we have to create a new keymap. We can make a copy of org-mouse-map and add new keys to it that are specific to this link. #+BEGIN_SRC emacs-lisp (defun prev-link () (interactive) (re-search-backward "keym:" nil t)) (defun next-link () (interactive) (re-search-forward "keym:" nil t)) (org-add-link-type "keym" (lambda (path) (interactive) (message "You followed me.")) nil :keymap (let ((map (copy-keymap org-mouse-map))) (define-key map (kbd "C-") 'prev-link) (define-key map (kbd "C-") 'next-link) (define-key map (kbd "C-") (lambda ()(interactive)(message-box "special C-up"))) (define-key map [s-mouse-1] (lambda () (interactive) (message-box "s-Followed"))) map)) #+END_SRC #+RESULTS: : Created keym link. keym:one then keym:two and finally keym:three ** a completion example with a dynamic face for validation This example shows how to add a completion function, and use a dynamic face to show when a bad link has been made (in this case there are 4 allowed fruits, and anything else should be red. #+BEGIN_SRC emacs-lisp (defun my-comp (&optional arg) (format "fruit:%s" (completing-read "Choose a fruit: " '("apple" "orange" "grapes" "kiwi")))) (defun fruit-link-face (path) (if (member path '("apple" "orange" "grapes" "kiwi")) 'org-link '(:foreground "red"))) (defun fruit-tooltip (_win _obj position) (save-match-data (save-excursion (goto-char position) (let ((path (org-element-property :path (org-element-context)))) (if (member path '("apple" "orange" "grapes" "kiwi")) "A fruit" (format "%s: Illegal value. Must be one of apple, orange, grapes or kiwi." path)))))) (org-add-link-type "fruit" nil nil :help-echo 'fruit-tooltip :face 'fruit-link-face :complete 'my-comp) #+END_SRC #+RESULTS: : Created fruit link. [[fruit:apple]] [[fruit:orange][an orange in brackets]] a bad fruit:grapefruit. [[fruit:kiwi]] ** a store link example [[head:*a%20store%20link%20example][a store link example]] #+BEGIN_SRC emacs-lisp (defun store-my-headline () (when (and (eq major-mode 'org-mode) (org-at-heading-p)) (org-store-link-props :type "head" :link (format "head:*%s" (nth 4 (org-heading-components))) :description (nth 4 (org-heading-components))))) (defun follow-head (path) (org-open-link-from-string (format "[[%s]]" path))) (org-add-link-type "head" 'follow-head nil :store 'store-my-headline) #+END_SRC #+RESULTS: : Created head link. ** an activate-func example You may want to do some additional things when a link is activated. For example, maybe it makes sense for different parts of the link to have different actions, or colors. Here is an example where we make an rgb link of three numbers, and color each number, and make the link color dynamic. This is an rgb link with three comma separated numbers. We color each number accordingly, and set the rgb link to the color represented by the RGB pair. rgb:238,130,238 This is a violet color. rgb:225,225,225 This is a light gray. A subtle point in this example is the need to save-match-data. Some functions modify the match-data, and this will mess up the whole font-lock system. #+BEGIN_SRC emacs-lisp (require 'color) (defun rgb-face (path) (let* ((f (split-string path ",")) (red (/ (string-to-number (nth 0 f)) 255.0)) (green (/ (string-to-number (nth 1 f)) 255.0)) (blue (/ (string-to-number (nth 2 f)) 255.0)) (hex (color-rgb-to-hex red green blue))) (list :foreground hex))) (defun rgb-func (start end path bracketp) (save-excursion (goto-char start) (save-match-data (cl-loop for num in (split-string path ",") for face in (list '(:foreground "red") '(:foreground "green") '(:foreground "blue")) do (progn (re-search-forward num end t) (add-text-properties (match-beginning 0) (match-end 0) (list 'face face))))))) (org-add-link-type "rgb" nil nil :face 'rgb-face :activate-func 'rgb-func) #+END_SRC #+RESULTS: : Created rgb link. -- Professor John Kitchin Doherty Hall A207F Department of Chemical Engineering Carnegie Mellon University Pittsburgh, PA 15213 412-268-7803 @johnkitchin http://kitchingroup.cheme.cmu.edu