Browse Source

Links: Implement special completion support for some link types

The commit implements a general mechanism for providing special
(e.g. completion) support for specific link types when entering links
with `C-c C-l'.  After calling `C-c C-l', you may now press RET after
inserting a link prefix, and Org will look for a function
`org-PREFIX-complete-link'.  Such functions may be defined for any
link types, including link abbreviations.  Currently, Org has
`org-file-complete-link' for file name completion, and
`org-bbdb-complete-link' for completion of record names from BBDB.
Carsten Dominik 16 years ago
parent
commit
762736d18d
5 changed files with 107 additions and 55 deletions
  1. 5 0
      doc/ChangeLog
  2. 35 23
      doc/org.texi
  3. 9 0
      lisp/ChangeLog
  4. 5 0
      lisp/org-bbdb.el
  5. 53 32
      lisp/org.el

+ 5 - 0
doc/ChangeLog

@@ -1,3 +1,8 @@
+2009-05-10  Carsten Dominik  <carsten.dominik@gmail.com>
+
+	* org.texi (Handling links): Document type-specific completion
+	when inserting links.
+
 2009-05-06  Carsten Dominik  <carsten.dominik@gmail.com>
 
 	* orgcard.tex: Document the key for sorting.

+ 35 - 23
doc/org.texi

@@ -2878,30 +2878,34 @@ The key binding @kbd{C-c l} is only a suggestion - see @ref{Installation}.
 @cindex inserting links
 @item C-c C-l
 @vindex org-keep-stored-link-after-insertion
-Insert a link.  This prompts for a link to be inserted into the buffer.  You
-can just type a link, using text for an internal link, or one of the link
-type prefixes mentioned in the examples above.  All links stored during the
-current session are part of the history for this prompt, so you can access
-them with @key{up} and @key{down} (or @kbd{M-p/n}).  Completion, on the other
-hand, will help you to insert valid link prefixes like @samp{http:} or
-@samp{ftp:}, including the prefixes defined through link abbreviations
-(@pxref{Link abbreviations}).  The link will be inserted into the
-buffer@footnote{After insertion of a stored link, the link will be removed
-from the list of stored links.  To keep it in the list later use, use a
-triple @kbd{C-u} prefix argument to @kbd{C-c C-l}, or configure the option
+Insert a link@footnote{ Note that you don't have to use this command to
+insert a link.  Links in Org are plain text, and you can type or paste them
+straight into the buffer.  By using this command, the links are automatically
+enclosed in double brackets, and you will be asked for the optional
+descriptive text.}.  This prompts for a link to be inserted into the buffer.
+You can just type a link, using text for an internal link, or one of the link
+type prefixes mentioned in the examples above.  The link will be inserted
+into the buffer@footnote{After insertion of a stored link, the link will be
+removed from the list of stored links.  To keep it in the list later use, use
+a triple @kbd{C-u} prefix argument to @kbd{C-c C-l}, or configure the option
 @code{org-keep-stored-link-after-insertion}.}, along with a descriptive text.
 If some text was selected when this command is called, the selected text
-becomes the default description.@* Note that you don't have to use this
-command to insert a link.  Links in Org are plain text, and you can type
-or paste them straight into the buffer.  By using this command, the links are
-automatically enclosed in double brackets, and you will be asked for the
-optional descriptive text.
-@c
-@c  If the link is a @samp{file:} link and
-@c the linked file is located in the same directory as the current file or
-@c a subdirectory of it, the path of the file will be inserted relative to
-@c the current directory.
-@c
+becomes the default description.
+
+@b{Inserting stored links}@*
+All links stored during the
+current session are part of the history for this prompt, so you can access
+them with @key{up} and @key{down} (or @kbd{M-p/n}).
+
+@b{Completion support}@* Completion with @key{TAB} will help you to insert
+valid link prefixes like @samp{http:} or @samp{ftp:}, including the prefixes
+defined through link abbreviations (@pxref{Link abbreviations}).  If you
+press @key{RET} after inserting only the @var{prefix}, Org will offer
+specific completion support for some link types@footnote{This works by
+calling a special function @code{org-PREFIX-complete-link}.}  For
+example, if you type @kbd{file @key{RET}}, file name completion (alternative
+access: @kbd{C-u C-c C-l}, see below) will be offered, and after @kbd{bbdb
+@key{RET}} you can complete contact names.
 @kindex C-u C-c C-l
 @cindex file name completion
 @cindex completion, of file names
@@ -3045,7 +3049,10 @@ can define them in the file with
 
 @noindent
 In-buffer completion @pxref{Completion} can be used after @samp{[} to
-complete link abbreviations.
+complete link abbreviations.  You may also define a function
+@code{org-PREFIX-complete-link} that implements special (e.g. completion)
+support for inserting such a link with @kbd{C-c C-l}.  Such a function should
+not accept any arguments, and return the full link with prefix.
 
 @node Search options, Custom searches, Link abbreviations, Hyperlinks
 @section Search options in file links
@@ -10367,6 +10374,11 @@ can also set the @code{:description} property to provide a default for
 the link description when the link is later inserted into an Org
 buffer with @kbd{C-c C-l}.
 
+When is makes sense for your new link type, You may also define a function
+@code{org-PREFIX-complete-link} that implements special (e.g. completion)
+support for inserting such a link with @kbd{C-c C-l}.  Such a function should
+not accept any arguments, and return the full link with prefix.
+
 @node Context-sensitive commands, Tables in arbitrary syntax, Adding hyperlink types, Hacking
 @section Context-sensitive commands
 @cindex context-sensitive commands, hooks

+ 9 - 0
lisp/ChangeLog

@@ -1,3 +1,12 @@
+2009-05-10  Carsten Dominik  <carsten.dominik@gmail.com>
+
+	* org.el (org-link-try-special-completion)
+	(org-file-complete-link): New functions.
+	(org-insert-link): Add special completion support for some link
+	types.
+
+	* org-bbdb.el (org-bbdb-complete-link): New function.
+
 2009-05-08  Carsten Dominik  <carsten.dominik@gmail.com>
 
 	* org.el (org-cycle): Remove erraneous space character.

+ 5 - 0
lisp/org-bbdb.el

@@ -338,6 +338,11 @@ This is used by Org to re-create the anniversary hash table."
     (when text
       (mapconcat 'identity text "; "))))
 
+(defun org-bbdb-complete-link ()
+  "Read a bbdb link with name completion."
+  (concat "bbdb:"
+	  (bbdb-record-name (car (bbdb-completing-read-record "Name: ")))))
+
 (provide 'org-bbdb)
 
 ;; arch-tag: 9e4f275d-d080-48c1-b040-62247f66b5c2

+ 53 - 32
lisp/org.el

@@ -7356,7 +7356,7 @@ used as the link location instead of reading one interactively."
 	 (desc region)
 	 tmphist ; byte-compile incorrectly complains about this
 	 (link link-location)
-	 entry file)
+	 entry file all-prefixes)
     (cond
      (link-location) ; specified by arg, just use it.
      ((org-in-regexp org-bracket-link-regexp 1)
@@ -7374,26 +7374,12 @@ used as the link location instead of reading one interactively."
 			      (org-remove-angle-brackets (match-string 0)))))
      ((member complete-file '((4) (16)))
       ;; Completing read for file names.
-      (setq file (read-file-name "File: "))
-      (let ((pwd (file-name-as-directory (expand-file-name ".")))
-	    (pwd1 (file-name-as-directory (abbreviate-file-name
-					   (expand-file-name ".")))))
-	(cond
-	 ((equal complete-file '(16))
-	  (setq link (org-make-link
-		      "file:"
-		      (abbreviate-file-name (expand-file-name file)))))
-	 ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file)
-	  (setq link  (org-make-link "file:" (match-string 1 file))))
-	 ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
-			(expand-file-name file))
-	  (setq link  (org-make-link
-		       "file:" (match-string 1 (expand-file-name file)))))
-	 (t (setq link (org-make-link "file:" file))))))
+      (setq link (org-get-file-link complete-file)))
      (t
       ;; Read link, with completion for stored links.
       (with-output-to-temp-buffer "*Org Links*"
-	(princ "Insert a link.  Use TAB to complete valid link prefixes.\n")
+	(princ "Insert a link.
+Use TAB to complete link prefixes, then RET for type-specific completion support\n")
 	(when org-stored-links
 	  (princ "\nStored links are available with <up>/<down> or M-p/n (most recent with RET):\n\n")
 	  (princ (mapconcat
@@ -7403,24 +7389,31 @@ used as the link location instead of reading one interactively."
       (let ((cw (selected-window)))
 	(select-window (get-buffer-window "*Org Links*"))
 	(setq truncate-lines t)
-	(org-fit-window-to-buffer)
-	(select-window cw))
+	(unless (pos-visible-in-window-p (point-max))
+	  (org-fit-window-to-buffer))
+	(and (window-live-p cw) (select-window cw)))
       ;; Fake a link history, containing the stored links.
       (setq tmphist (append (mapcar 'car org-stored-links)
 			    org-insert-link-history))
+      (setq all-prefixes (append (mapcar 'car org-link-abbrev-alist-local)
+				 (mapcar 'car org-link-abbrev-alist)
+				 org-link-types))
       (unwind-protect
-	  (setq link
-		(let ((org-completion-use-ido nil))
-		  (org-completing-read
-		   "Link: "
-		   (append
-		    (mapcar (lambda (x) (list (concat (car x) ":")))
-			    (append org-link-abbrev-alist-local org-link-abbrev-alist))
-		    (mapcar (lambda (x) (list (concat x ":")))
-			    org-link-types))
-		   nil nil nil
-		   'tmphist
-		   (or (car (car org-stored-links))))))
+	  (progn
+	    (setq link
+		  (let ((org-completion-use-ido nil))
+		    (org-completing-read
+		     "Link: "
+		     (mapcar (lambda (x) (list (concat x ":")))
+			     all-prefixes)
+		     nil nil nil
+		     'tmphist
+		     (or (car (car org-stored-links))))))
+	    (if (or (member link all-prefixes)
+		    (and (equal ":" (substring link -1))
+			 (member (substring link 0 -1) all-prefixes)
+			 (setq link (substring link 0 -1))))
+		(setq link (org-link-try-special-completion link))))
 	(set-window-configuration wcf)
 	(kill-buffer "*Org Links*"))
       (setq entry (assoc link org-stored-links))
@@ -7482,6 +7475,34 @@ used as the link location instead of reading one interactively."
     (if remove (apply 'delete-region remove))
     (insert (org-make-link-string link desc))))
 
+(defun org-link-try-special-completion (type)
+  "If there is completion support for link type TAPE, offer it."
+  (let ((fun (intern (concat "org-" type "-complete-link"))))
+    (if (functionp fun)
+	(funcall fun)
+      (read-string "Link (no completion support): " (concat type ":")))))
+
+(defun org-file-complete-link (&optional arg)
+  "Create a file link using completion."
+  (let (file)
+    (setq file (read-file-name "File: "))
+    (let ((pwd (file-name-as-directory (expand-file-name ".")))
+	  (pwd1 (file-name-as-directory (abbreviate-file-name
+					 (expand-file-name ".")))))
+      (cond
+       ((equal arg '(16))
+	(setq link (org-make-link
+		    "file:"
+		    (abbreviate-file-name (expand-file-name file)))))
+       ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file)
+	(setq link  (org-make-link "file:" (match-string 1 file))))
+       ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
+		      (expand-file-name file))
+	(setq link  (org-make-link
+		     "file:" (match-string 1 (expand-file-name file)))))
+       (t (setq link (org-make-link "file:" file))))))
+  link)
+
 (defun org-completing-read (&rest args)
   "Completing-read with SPACE being a normal character."
   (let ((minibuffer-local-completion-map