|
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 )
)