This page shows a example of writing a emacs lisp function that creates a customized HTML link. If you don't know elisp, first take a gander at Emacs Lisp Basics.
I want to write a command that changes the current word into a HTML link. Examples:
ellipse ⇒ <a href="../ellipse/ellipse.html">ellipse</a>ellipse ⇒ <a href="../../curves/ellipse/ellipse.html">ellipse</a>The exact path of the link depends on the current file's location and existing file names and directory structure where the current file is.
I have a math dictionary website, with directory structure like this:
curves/circle/circle.html curves/ellipse/ellipse.html curves/parabola/parabola.html curves/hyperbola/hyperbola.html curves/spiral/spiral.html curves/cycloid/cycloid.html …
Each of the page has many cross-reference links to other pages.
Suppose am writing the circle page. Suppose i write: “circle is a special case of ellipse”. While the cursor is on the word “ellipse”, i want to press a button, and it changes to a link to the ellipse page.
Note that the path for the HTML link is not always the same. It depends on the current file's location.
For sample pages, see: Conic Sections ◇ Hyperboloid of One Sheet.
Here's the basic steps:
Getting the word under cursor can be done like this:
(setq cursorWord
(if (region-active-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(thing-at-point 'word)
))
For detail, see: Emacs Lisp: Using thing-at-point.
Here's the part that constructs a list of all possible paths to check:
;; the paths to test (setq testPaths (vector (concat "~/web/xahlee_org/SpecialPlaneCurves_dir/" (upcase-initials wordPath) "_dir/" wordPath ".html") (concat "~/web/xahlee_org/surface/" wordPath "/" wordPath ".html")))
Now, we can check file existence like this:
;; loop thru the paths until a file is found (setq ξfound-p nil) (setq ξi 0) (while (and (not ξfound-p) (< ξi (length testPaths))) (setq rPath (elt testPaths ξi)) (setq ξfound-p (file-exists-p rPath)) (setq ξi (1+ ξi)))
If found, then delete the word under cursor, and construct the link and insert it.
(if ξfound-p (progn (setq linkWord (replace-regexp-in-string "_" " " cursorWord)) (delete-region p1 p2) (insert (concat "<a href=\"" (file-relative-name rPath) "\">" linkWord "</a>"))) (progn (beep) (message "No file found")))
If not found, beep and print a message.
In elisp, function or variable names that's used for true/false usually ends in “p”, by convention. (“p” for “predicate”, from study of logic.) For example: integerp, vectorp, region-active-p, ….
(defun xah-curve-linkify () "Make the current word or text selection into a HTML link. This function works on Xah Lee's website only. Example: “parabola” becomes “<a href=\"../Parabola_dir/parabola.html\">parabola</a>”. The directory to search includes: “SpecialPlaneCurves_dir” and “surface”." (interactive) (let (bds p1 p2 cursorWord wordPath ξi testPaths ξfound-p rPath linkWord) (setq bds (get-selection-or-unit 'glyphs)) (setq cursorWord (elt bds 0) ) (setq p1 (aref bds 1) ) (setq p2 (aref bds 2) ) ;; word for constructing possible dir (setq wordPath (replace-regexp-in-string " " "_" (downcase cursorWord))) ;; the paths to test (setq testPaths (vector (concat "~/web/xahlee_org/SpecialPlaneCurves_dir/" (upcase-initials wordPath) "_dir/" wordPath ".html") (concat "~/web/xahlee_org/surface/" wordPath "/" wordPath ".html"))) ;; loop thru the paths until a file is found (setq ξfound-p nil) (setq ξi 0) (while (and (not ξfound-p) (< ξi (length testPaths))) (setq rPath (elt testPaths ξi)) (setq ξfound-p (file-exists-p rPath)) (setq ξi (1+ ξi))) (if ξfound-p (progn (setq linkWord (replace-regexp-in-string "_" " " cursorWord)) (delete-region p1 p2) (insert (concat "<a href=\"" (file-relative-name rPath) "\">" linkWord "</a>"))) (progn (beep) (message "No file found")))))
In the code above, i used my own library get-selection-or-unit to grab the word under cursor, but you can just use thing-at-point.
The weird ξ you see in my elisp code is Greek x. I use Unicode char in symbol name for easy distinction from builtin symbols. You can just ignore it. 〔☛ Programing Style: Variable Naming: English Words Considered Harmful〕
Emacs ♥
blog comments powered by Disqus