Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
; ; Copyright (c) 2004-2007 by Keith M. Knowles. ; Free software licenced under the terms of the ; GNU Lesser General Public Licence. ; ; ; Program: Elinks. ; Module: elinks.el -- hypertext capability. ; Version: 1 ; Author: Keith M. Knowles. ; Date: Feb 2004 ; ; ; Changes: ; ; 07/12/13 kmk Allowed '-' in tag names. ; 07/12/13 kmk Define next/prev-link and bind C-> and C-<. ; 07/12/08 kmk Timestamp was appearing as yyddmm. ; 07/12/04 kmk Add time-stamping for Iweb. ; 07/12/04 kmk Define kp-2, 4, 5, 6 and 8 as synonyms. ; 07/09/26 kmk Fix a /tag logic error at the beginning of buffer ; that prevented recording of the return link. ; 07/09/24 kmk Make elinks-widen stack a history entry for return. ; 07/09/21 kmk Include linked documentation in this file. ; 07/08/12 kmk Completed 5/28 work and clean-up. ; 07/07/22 kmk Implement < /tag > to control narrowing. ; 06/05/28 kmk Use regexp to drive elinks. ; 06/04/23 kmk Implement link-translation. ; 05/01/30 kmk Change < topic > to < tag >. ; 05/01/25 kmk Switch to file#tag notation. ; 04/12/28 kmk Change link format to: "tag1 < see tag2 [file] >". ; 04/11/29 kmk Interpret line numbers and search strings ; 04/05/05 kmk Implement % to return to last place. ; 04/03/12 kmk Include incremental search for tag. ; 04/02/07 kmk Implement hyper-link capability in text files. ; ; ; Description: <see #root> ; ; <tag root>; ; ; Elinks -- hyper-text in Emacs ; ; If you are unfamiliar with using Elinks, press C-. to follow this link: ; <see #summary>. ; ; Elinks provides hyper-linking in plain-text files for use within Emacs. ; ; Elinks provides poor-man's browsing in Emacs by following hyper-links ; embedded in the text in the form of "see" directives. A hyper-link ; refers to its target using a file#tag format, specifying a location ; within a file. These directives link topics together. History is kept ; to allow return. ; ; Topics are delineated with the "tag" directive. A tag can be a target ; for a hyper-link and viewed as an open or closed topic. ; ; An open topic is viewed in the file along with whatever contents ; surround it. For example, a target topic might be a comment in a source ; file. In this case, you wish to also see the source code the comment ; applies to. ; ; A closed topic is viewed in isolation effectively as a separate "page" ; of information. (This is done in Emacs by narrowing the window.) ; ; Elinks is partnered by Docgen, a separate utility that generates ; browsable HTML pages from plain-text files, recognizing Elinks in order ; to link pages. ; ; Elinks depends upon the file, menu.el. ; ; Subtopics: ; 1. <see #see "see" directive> ; 2. <see #tag "tag" directive> ; 3. <see #ops Elink operations> ; 4. <see #ex an example page> ; 5. <see #notes To be done> ; </tag> ; ; ; <tag ex>; <see #root up:> ; <see #ops prev:> <see #notes next:> ; An example of page layout ; ; This is an example of how a topic page might be laid out. Each topic ; should fit in one window. In this example, explanatory text follows ; the title. The topic ends with a list of links to subtopics. ; ; Note that because the explanatory text may contain cross-links, (which ; would appear in the down-link menu, an author might choose to put the ; table of subtopics first, immediately after the title, and then with the ; explanatory text. This style might also assist the reader who seeks to ; quickly "drill down" to a particular subject. ; ; Subtopics: ; 1. < see #subtop1 subtop1 decription > ; 2. < see #subtop2 subtop2 decription > ; 3. < see #subtop3 subtop3 decription > ; .. ; .. ; 8. < see #subtop8 subtop8 decription > ; </tag> ; ; ; Notes: <tag notes>; <see #root up:> ; <see #ex prev:> ; Elinks -- to be done ; ; - should we narrow when going to < tag >? ; - <refs ../../../databases/sys/inc/lang11.inc> allows "lang11.inc" only ; thereafter. <see elinks/elinks_loc> ; - error when the file name is only 1 character ; - error when < tag > in target file is undefined ; - illegal menu option causes bug. ; - move this documentation into emacs/elinks.el. ; - menu bug: ; 1. <see #see "see" directive> ; 2. missing choice in Ilog ; </tag> ; ( setq-default elinks-stack nil ) ; browse stack ; <tag summary>; <see #root up: Elinks root> ; ; Elinks -- quick start ; ; C-> move to the next link in the buffer, <see #link-next> ; C-< move to the previous link in the buffer, <see #link-prev> ; ; C-. follow a see-link, such as <see #follow> ; C-, return back via the last link followed, <see #return> ; ; A page _may_ have up, left, right and down pointers linking the page ; into a hierarchy of topics. There may be numerous down-links and these ; will be presented as a menu for selection. ; ; C-kp-up go up to the parent topic, <see #up> ; C-kp-left go to the previous topic, <see #prev> ; C-kp-right go to the next topic, <see #next> ; C-kp-down present a menu of subtopics, <see #menu> ; </tag> ; <tag ops>; <see #root up:> ; <see #tag prev:> <see #notes next:> ; Elinks -- operations: ; ; The operations implemented by Elinks are: ; ; 1. <see #next-link elinks-next-link> C-> ; 2. <see #prev-link elinks-prev-link> C-< ; ; 3. <see #follow elinks-follow> C-. ; 4. <see #return elinks-return> C-, ; ; 5. <see #menu elinks-menu> C-kp-down ; 6. <see #next elinks-next-topic> C-kp-right ; 7. <see #up elinks-up> C-kp-up ; 8. <see #prev elinks-prev-topic> C-kp-left ; ; 9. <see #widen elinks-widen> C-kp-space (KP5) ; ; Topics may be linked together in a hierarchical structure in which each ; topic, (except for the "root" topic), has a parent topic. The parent ; topics should be linked to their subtopics via down-links, preferably ; presented in a tabular, menu form. "Next", (and possibly "prev" links), ; linking subtopics in a natural, sequential reading order complete the ; hierarchy. ; ; Note however that "cross-links" may additionally exist in a topic to ; allow "surfing" outside the natural hierarchical reading order. There ; are at least three possible ways to use documentation: ; ; 1. read a document in sequential order to absorb its content; ; 2. "drill down" through the menus from the top to locate information; ; 3. "surf" from topic to related topic to search for infomration in an ; unknown location in the documentation. ; ; Elinks follow and return support surfing cross-links and the menu, next, ; up and prev operations support hierarchical navigation. ; ; NB: the next and prev links are considered error-prone and are not ; necessary for use with Docgen, which discovers those relationships ; automatically. Next-links may nevertheless be convenient for "poor man" ; browsing in Emacs. Prev-links are considered almost completely useless ; and are provided for symmetry and little other reason. (The Elinks ; return operation is considered quite sufficient for the limited case in ; which a reader wishes to retrace his steps in that just read in order.) ; </tag> ; ( global-set-key [?\C-.] 'elinks-follow ) ; <see #follow> ( global-set-key [?\C-,] 'elinks-return ) ; <see #return> ( global-set-key [?\C->] 'elinks-next-link ) ( global-set-key [?\C-<] 'elinks-prev-link ) ( global-set-key [C-kp-up] 'elinks-up ) ( global-set-key [C-kp-8] 'elinks-up ) ( global-set-key [C-kp-down] 'elinks-menu ) ; <see #menu> ( global-set-key [C-kp-2] 'elinks-menu ) ; <see #menu> ( global-set-key [C-kp-left] 'elinks-prev-topic ) ( global-set-key [C-kp-4] 'elinks-prev-topic ) ( global-set-key [C-kp-right] 'elinks-next-topic ) ; <see #next> ( global-set-key [C-kp-6] 'elinks-next-topic ) ; <see #next> ( global-set-key [C-kp-space] 'elinks-widen ) ; <see #widen> ( global-set-key [C-kp-5] 'elinks-widen ) ; <see #widen> ; <tag see>; <see #root up:> ; <see #tag next:> ; Elinks -- the 'see' directive: ; ; The see directive is an HTML-style directive taking the form: ; ; < see file#tag label > ; ; The file is optional and defaults to the current file. ; ; The #tag is optional and defaults to the last position in the file used ; by Emacs, or to the top of the file. The tag can be: ; ; . top of file ; $ end of file ; % position last remembered by Emacs ; 123 line number ; "target" literal text (searched for from top of file) ; name name of a topic defined in a tag directive ; ; The label argument is optional and labels the link. It is used by the ; <see #menu> command. ; ; In addition, file-name short-cuts are implemented, using a //link ; prefix notation. <see #short> ; </tag> ; ; <tag follow>; <see #ops up:> ; <see #return next:> ; Elinks -- C-. : follow ; ; Scan forward to the next elink, <see #see>, and follow it. If a tag ; is specified, find and follow the corresponding topic or location in ; the destination buffer. ; ; </tag> ; ( defun elinks-follow ( &optional ref ) "Follow next Elink" ( interactive ) ( let ( file ( pos ( point ) ) ; original position ) ; If the ref is specified, position to search the whole, visible buffer. ; ( if ( not ref ) ( setq tail "\\(?:\\|[ \t\n]+\\([^>]*\\)\\)?[ \t\n]*>" ) ( beginning-of-buffer ) ( setq tail ( concat "[ \t\n]+\\(" ref "[^>]*\\)[ \t\n]*>" ) ) ) ; Locate the target reference and position before the keyword. ; ( if ( not ( re-search-forward ( concat "<see[ \t\n]+" ; verb "\\([^ \t\n#>]*\\)" ; file "\\(?:#\\(\." ; top of file "\\|%" ; last position "\\|\$" ; end of file "\\|[A-Za-z0-9_-]+" ; tag or line number "\\|\".*?\"\\)\\)?" ; target string (non-greedy?) tail ; tail ) nil t ) ) ( progn ; abort ( goto-char pos ) ; leave point at original position ( if ref ( error ( concat "No Elink referring to: " ref ) ) ( error ( concat "No Elink following current position" ) ) ) ) ) ( setq pos ( point ) ) ( setq file ( match-string 1 ) ) ( setq tag ( match-string 2 ) ) ( setq ref ( match-string 3 ) ) ; the full ref ( if ( equal file "" ) ( setq file nil ) ) ( if ( or ( not tag ) ( equal tag "" ) ) ( setq tag "." ) ) ( if ( equal ref "" ) ( setq ref nil ) ) ; We need to here detect a timestamp on the beginning of the line and ; update it with today's date. If there, it will have the format: ; ; yymmdd. ; ; where '.' is a space or tab. ; ( beginning-of-line ) ( if ( looking-at "[0-9][0-9][0-9][0-9][0-9][0-9][ \t]" ) ( progn ( setq today ( calendar-current-date ) ) ( insert-string ( format "%02d%02d%02d" ( - ( nth 2 today ) 2000 ) ( nth 0 today ) ( nth 1 today ) ) ) ( kill-word 1 ) ) ) ( goto-char pos ) ; <tag short> ; <see #see up:> ; ; Elinks -- file short-cuts: ; ; If a file-specifiation begins with the notation, //link, ; Elinks consults the redirection file, ~/.apps/elinks, which ; should contain entries of the form: ; ; link:file ; ; The //link prefix is replaced with the corresponding file ; found in the elinks redirection file. This is not, but could be ; recursive? ; </tag> ; ( if file ( if ( and ( >= ( length file ) 2 ) ( equal ( substring file 0 2 ) "//" ) ) ( save-window-excursion ( setq file ( substring file 2 ) ) ( setq slash ( string-match "/" file ) ) ( if slash ( progn ( setq prefix ( substring file 0 slash ) ) ( setq postfix ( substring file slash ) ) ) ( setq prefix file ) ( setq postfix nil ) ) ; look up the prefix in the elinks file. ( find-file "~/.apps/elinks" ) ( beginning-of-buffer ) ( setq pos ( search-forward ( concat prefix ":" ) nil t ) ) ( if ( not pos ) ( error ( concat "No translation for " prefix ) ) ) ( setq start ( point ) ) ( end-of-line ) ( setq prefix ( buffer-substring start ( point ) ) ) ( setq file ( concat prefix postfix ) ) ) ) ) ; Save return position. ; ( setq pos ( point-marker ) ) ( if file ( find-file file ) ) ( widen ) ; <tag tag> ; <see #root up:> ; <see #see prev:> <see #ops next:> ; Elinks -- the 'tag' directive: ; ; < tag tagname label > ; ; Use <see #follow> as an example. ; ; One possibility for simplifying parsing is to place the up tag in ; the /tag directive. This is not so intuitive and it restricts up- ; linking to closed topics. ; ; But I think the better one is to put all the down-links in the ; topic, possibly in a table. Then the "next:" link. Then the "up:" ; link. Then, the "up2:", etc, links. ; ; We need to balance the Elink and HTML appearance. A plain-text ; topic will appear along with the one generated by Docgen from the ; tag directive. ; </tag> ; ; Find the referenced topic. If not found, no diagnostic is issued and ; the buffer is left positioned at its beginning. [kmk] which is not ; desirable. ; ; . top of file ; $ end of file ; % last position remembered by Emacs ; num line number ; "tag" search for the tag ; topic <tag topic> ; ( if ( not ( string-equal tag "%" ) ) ( progn ( beginning-of-buffer ) ( if ( not ( string-equal tag "." ) ) ( if ( string-equal tag "$" ) ( end-of-buffer ) ( if ( /= ( string-to-number tag ) 0 ) ( goto-line ( string-to-number tag ) ) ( if ( string-equal ( substring tag 0 1 ) "\"") ( search-forward ( substring tag 1 -1 ) nil t ) ( re-search-forward ( concat "<tag[ \t\n]+" tag "\\(\\|[ \t\n]*[^>]*\\)>" ) nil t ) ) ) ( recenter 0 ) ) ) ) ) ( setq start ( point ) ) ( if ( re-search-forward "\\(<tag[ \t\n]\\|</tag>\\)" nil t ) ( progn ( backward-char 5 ) ( if ( looking-at "/tag" ) ( narrow-to-region start ( - ( point ) 1 ) ) ) ( goto-char start ) ) ) ; Success. Remember the previous page location. ; ( push pos elinks-stack ) ) ) ; The following needs modification for ref. ; ; <tag menu>; <see #ops up: ops> ; <see #return prev:> <see #next next:> ; Elinks -- C-kp-down : menu ; ; The Elinks "menu" operation scans the current topic page and presents a ; menu of elinks found there. This allows the reader an easy method to ; choose a subtopic of the page and navigate directly there. ; ; Note however that the menu operation will discover every link on the ; page and this will possibly include up-, prev- and next-links, as well ; as cross-links. These do not link to subtopics of the page, however, ; with care, this should not lead to confusion. ; ; This page has no subtopics, so for an example of using "menu", first use ; "up" to return to the operations topic above and then use "menu" to ; select a subtopic; this one, elinks-menu (option "f"?), for example. ; </tag> ; ( defun elinks-menu ( ) "Follow text-link to specified tag" ( interactive ) ( setq link-tags nil ) ( setq link-pos nil ) ( save-excursion ( beginning-of-buffer ) ( while ( re-search-forward ( concat "<see[ \t\n]+" ; verb "\\([^ \t\n#>]*\\)" ; file "\\(?:" "#\\(\." ; top of file "\\|%" ; last position "\\|\$" ; end of file "\\|[A-Za-z0-9_-]+" ; tag or line number "\\|\".*?\"\\)\\)?" ; target string (non-greedy?) "\\(?:[ \t\n]+\\([^>]*\\)\\)?" ; ref "[ \t\n]*>" ; tail ) nil t ) ( setq link-tag ( match-string 3 ) ) ( if ( not link-tag ) ( progn ( setq link-tag ( match-string 2 ) ) ( if ( not link-tag ) ( setq link-tag ( match-string 1 ) ) ) ) ) ( if link-tag ( progn ( push link-tag link-tags ) ( push ( match-beginning 0 ) link-pos ) ) ) ) ) ( setq link-tags ( nreverse link-tags ) ) ( setq link-pos ( nreverse link-pos ) ) ( setq link-tag ( mini-menu link-tags ) ) ( if link-tag ( progn ( goto-char ( elt link-pos link-tag ) ) ( elinks-follow ) ) ) ) ; <tag return>; <see #ops up:> ; <see #follow prev:> <see #menu next:> ; Elinks -- C-, : return ; ; The <see #follow> operation keeps a history of visited links. The ; "return" operation pops the most recent entry from the history stack and ; navigates back to the corresponding, originating link. ; ; </tag> ; ( defun elinks-return ( ) "Return from text-link" ( interactive ) ( let ( prev ) ( setq prev ( pop elinks-stack ) ) ( if prev ( progn ( switch-to-buffer ( marker-buffer prev ) ) ( widen ) ( goto-char ( marker-position prev ) ) ( save-excursion ( if ( re-search-forward "\\(<tag[ \t\n]\\|</tag>\\)" nil t ) ( progn ( backward-char 5 ) ( if ( looking-at "/tag" ) ( progn ( setq end ( - ( point ) 1 ) ) ( re-search-backward "<tag[ \t\n]+[^>]+>" ) ( goto-char ( match-end 0 ) ) ( narrow-to-region ( point ) end ) ) ) ( goto-char start ) ) ) ) ) ( error "No previous page" ) ) ) ) ; <tag next-link>; <see #ops up:> ; <see #menu prev:>??? ; ; </tag> ; ( defun elinks-next-link ( ) "Position to the next link" ( interactive ) ( save-excursion ( forward-char 1 ) ( re-search-forward "<see[ \t\n]" ) ( backward-char 5 ) ( setq pos ( point ) ) ) ( goto-char pos ) ) ; <tag next>; <see #ops up:> ; <see #menu prev:> <see #up next:> ; Elinks -- C-kp-right : next ; ; This operation searches the current page for an elink marked with a ; description beginning with "next:" and follows it. This should take the ; reader to the next subtopic of the parent (of the current topic). ; </tag> ; ( defun elinks-next-topic ( ) "Follow the next-link" ( interactive ) ( elinks-follow "next:" ) ) ; <tag up>; <see #ops up:> ; <see #next prev:> <see #prev next:> ; Elinks -- C-kp-up : up ; ; This operation searches the current page for an elink marked with a ; description beginning with "up:" and follows it. This should take the ; reader to the parent of the current topic. ; </tag> ; ( defun elinks-up ( ) "Follow the up-link" ( interactive ) ( elinks-follow "up:" ) ) ; <tag prev-link>; ; ( defun elinks-prev-link ( ) "Position to the previous link" ( interactive ) ( save-excursion ( backward-char 1 ) ( re-search-backward "<see[ \t\n]" ) ( setq pos ( point ) ) ) ( goto-char pos ) ) ; <tag prev>; <see #ops up:> ; <see #up prev:> <see #widen next:> ; Elinks -- C-kp-left : prev ; ; This operation searches the current page for an elink marked with a ; description beginning with "prev:" and follows it. This should take the ; reader to the previous subtopic of the parent (of the current topic). ; ; Prev-links, like next-links, are considered error-prone. Note that both ; relationships are automatically discovered by Docgen. Nevertheless, ; next-links are at least useful for "poor man's browsing" in Emacs alone. ; Prev-links however are considered next to useless since, realistically, ; readers do not read a document in natural order, with the possible ; exception of perhaps backing up one or two topics in order to reread ; them; and this purpose can be achieved more sensibly by using the ; "return" operation to retrace recent history. The "prev" operation is ; provided merely for symmetry and that, reluctantly. ; </tag> ; ( defun elinks-prev-topic ( ) "Follow the prev-link" ( interactive ) ( elinks-follow "prev:" ) ) ; <tag widen>; <see #ops up:> ; <see #prev prev:> ; Elinks -- widen the view for editing ; ; This command, C-kp-space (KP5), is merely bound to the Emacs command, ; _widen_. This is helpful during editing of a document, particularly a ; "closed" topic. ; ; It can also be useful when the topic describes some associated source ; code. By widening the view, the surrounding source code may be exposed. ; This does, however, incur the cost that any up-, prev- and next-links on ; the page may not be interpreted properly since the corresponding ; operations will now search the whole file, rather than the narrow ; context of the topic, and thus may find other links, erroneously. ; ; 07/09/24 You can now use C-, (elinks-return) to re-narrow the view. ; </tag> ; ( defun elinks-widen ( ) "Widen the view to show the surrounds" ( interactive ) ; stack a history entry for elinks-return ( push ( point-marker ) elinks-stack ) ( widen ) )