How to view man page using Info in Emacs? - emacs

I can view man pages using info in the terminal:
info pthread_create
However, it is not possible with info in Emacs, even with info-apropos or info-menu.

EDIT:
It seems that fall-backs are not in the concept of Info-mode.
There follows a work-around applying advice. It does not work perfect but around the missing feature ;-).
It defines a fall-back for Info-goto-node (in Info-mode bound to g) and for Info-menu (in Info-mode bound to m).
Furthermore, it adds manual-apropos to info-apropos.
(require 'woman)
(defun Info-man-completion (_caller _info string predicate action)
"Add man entries to info completion."
;; prepare woman:
(unless (and woman-expanded-directory-path woman-topic-all-completions)
(setq woman-expanded-directory-path
(woman-expand-directory-path woman-manpath woman-path)
woman-topic-all-completions
(woman-topic-all-completions woman-expanded-directory-path)))
;; do completions:
(cond
((null action) ;; try-completion
;; shortest wins
(let ((_man (try-completion string woman-topic-all-completions)))
(cond
((eq _info t)
t)
((eq _man t)
t)
((and (stringp _info) (stringp _man))
(if (> (length _info) (length _man))
_man
_info))
((stringp _info)
_info)
(t _man)
)))
((eq action t) ;; all-completions
(let ((_man (all-completions string woman-topic-all-completions)))
(append _info _man)
))
((eq action 'lambda) ;; test-completion
(try-completion string _caller))
((eq action 'metadata) ;; state of current completion
'(metadata) ;; no specification
)))
;; args: string predicate code
(defadvice Info-read-node-name-1 (around man activate)
"Add man entries to info completion."
(setq ad-return-value (apply 'Info-man-completion 'Info-read-node-name-1 ad-do-it (ad-get-args 0))))
;;
(defadvice Info-complete-menu-item (around man activate)
"Add man entries to info completion."
(setq ad-return-value (apply 'Info-man-completion 'Info-complete-menu-item ad-do-it (ad-get-args 0))))
(defadvice Info-goto-node (around man activate)
"If no info node is found for string lookup and show man entry."
(condition-case err
ad-do-it
(user-error
(let ((err-str (car-safe (cdr err))))
(if (and (stringp err-str)
(string-match "No such node or anchor:" err-str))
(man (ad-get-arg 0))
(signal 'user-error err-str)
)))))
(defadvice Info-menu (around man activate)
"If no info menu entry is found for string lookup and show man entry."
(condition-case err
ad-do-it
(user-error
(let ((err-str (car-safe (cdr err))))
(if (and (stringp err-str)
(string-match "No such item in menu" err-str))
(man (ad-get-arg 0))
(signal 'user-error err-str)
)))))
(defadvice Info-apropos-find-node (after man activate)
"Add man appropos to info appropos."
(let (item)
(goto-char (point-max))
(let ((inhibit-read-only t))
(insert "\nMatches found by man-apropos\n\n")
(let ((beg (point))
(nodeinfo (assoc nodename Info-apropos-nodes)))
(if nodeinfo
(let ((search-string (nth 1 nodeinfo)))
(call-process "apropos" nil t t search-string)
(goto-char beg)
(while (re-search-forward "^\\(\\(?:[[:alnum:]]\\|\\s_\\)+\\)\\(?:[[:blank:]]+\\[\\]\\)?\\([[:blank:]]+([[:alnum:]]+)\\)[[:blank:]]+-[[:blank:]]+\\(.*\\)$" nil t)
(replace-match (replace-regexp-in-string "\\\\" "\\\\\\\\" (format "* %-38s.%s"
(format "%s:" (match-string 1))
(concat (match-string 1) (match-string 2))
(match-string 3))))))
(man nodename)
)))))
Info gives an error that the node is not available. Thereafter, the manual page is shown if there is one.

[Edited]
EmacsWiki says that iman:
Opens either an info format manual with InfoMode or a man page with
ManMode.
It links to the author's website:
http://homepage1.nifty.com/bmonkey/emacs/elisp/iman.el

Found M-x woman MANPAGE RET to most convenient way to call manpages from inside Emacs.

Related

How to extract XML processing instructions in Emacs Lisp?

I would like to extract the processing instructions (particularly xml-model) from an XML file; yet both (n)xml-parse-file as well as libxml-parse-xml-region do not recognize processing instructions.
Is there a clean way to extract processing instructions or do I have to regex search for PIs?
edit: Here is a first draft of the functionality I was looking for:
(cl-defun extract-processing-instructions (&rest processing-instructions)
"Extracts all/only the specified xml processing instructions from the current buffer and returns them as a list of string."
(interactive)
(let ((pi-re
(format "<\\?\\(%s\\).*\\?>" (string-join processing-instructions "\\|")))
(result))
(save-excursion
(goto-char (point-min))
(while (re-search-forward pi-re nil t)
(push (match-string 0) result)))
(nreverse result)))
(cl-defun pi-str2sexp (pi-str)
"Takes a processing instruction as a string and transforms it to a sexp-structure (in the style of xml-parse-*)."
(let (sexp attr-alist)
(save-match-data
;; get and push pi-element-name
;; (string-match "<\\?\\([[:alnum:]-]*\\)" pi-str)
(string-match "<\\?\\([[:alnum:]-]*\\)" pi-str)
(push (make-symbol (match-string 1 pi-str)) sexp)
;; construct attribute alist
(while (string-match "\\([[:alnum:]-]*\\)=\"\\([^ ]*\\)\""
pi-str (match-end 0))
(push (cons (make-symbol (match-string 1 pi-str))
(match-string 2 pi-str))
attr-alist)))
;; finally: push attr alist and return sexp
(push (nreverse attr-alist) sexp)
(nreverse sexp)))
edit 2: Turns out advicing/generally building upon xml-parse-* in this matter (like suggested by #Tom Regner) is a huge pain. :(
The thing I came up with was a context manager, the idea was to use it to around-advice string-parse-tag-1 (which is at the heart of xml-parse-* (of course stand-alone use is also an option):
(cl-defmacro --replace-first-group (regex-replace-alist)
`(save-excursion
(dolist (expression ,regex-replace-alist)
(goto-char (point-min))
(replace-regexp (car expression) (cadr expression)))))
(cl-defmacro with-parsable-pi (buffer &body body)
"Context manager that treats xml processing instructions in BUFFER as normal elements."
(declare (indent defun))
`(let ((old-buffer ,buffer))
(with-temp-buffer
(insert-buffer-substring old-buffer)
(goto-char (point-min))
(--replace-first-group '(("\\(\\?\\)>" "/>") ("<\\(\\?\\)" "<")))
,#body)))
This e.g. allows calls like
(with-parsable-pi (current-buffer)
(xml-parse-tag-1))
so it is at least possible to get an element at a time; but since the XML exposed in the context manager isn't actually valid and xml-parse-* (rightfully) errors if invalid XML is encountered, it isn't possible to process more than one element at a time.
I was thinking of maybe introducing a pseudo root element or something, but the kludge spiral is ghastly enough as it is.
Another idea of course would be to run an xpath query to extract processing instructions. If there only was a solid xpath solution in Emacs Lisp..
Ok, I think I found a satisfactory solution: xmltok-forward-prolog!
So here is the code I came up with for extracting processing instructions:
(cl-defun filter-xmltok-prolog (&optional (buffer (current-buffer))
(filter-re "processing-instruction-.*"))
"Filters the output of xmltok-forward-prolog (i.e. index 0 ('type') of each array) run in the context of BUFFER against FILTER-RE. Returns a list of vectors."
(with-current-buffer buffer
(save-excursion
(goto-char (point-min))
(let ((raw-prolog-data (xmltok-forward-prolog)))
(seq-filter
#'(lambda (x)
(string-match filter-re (symbol-name (aref x 0))))
raw-prolog-data)))))
(cl-defun --merge-pi-data (pi-data)
"Meant to operate on data filtered with filter-xmltok-prolog against 'processing-instruction-.*'.
Merges processing-instruction-left/-right and returns a list of vectors holding the start/end coordinates of a processing instruction at index 1 and 2."
(let ((left (car pi-data))
(right (cadr pi-data)))
(cond
((null pi-data) nil)
(t (cons
(vector 'processing-instruction
(aref left 1) (aref right 2))
(--merge-pi-data (cddr pi-data)))))))
;; test
(--merge-pi-data '([processing-instruction-left 40 51] [processing-instruction-right 52 126]))
(cl-defun pi-str2s-exp (pi-str)
"Takes a processing instruction as a string and transforms it into a sexp structure (in the style of xml-parse-*)."
(let (sexp attr-alist)
(save-match-data
;; get and push pi-element-name
(string-match "<\\?\\([[:alnum:]-]*\\)" pi-str)
(push (make-symbol (match-string 1 pi-str)) sexp)
;; construct attribute alist
(while (string-match "\\([[:alnum:]-]*\\)=\"\\([^ ]*\\)\""
pi-str (match-end 0))
(push (cons (make-symbol (match-string 1 pi-str))
(match-string 2 pi-str))
attr-alist)))
;; finally: push attr alist and return sexp
(push (nreverse attr-alist) sexp)
(nreverse sexp)))
(cl-defun get-processing-instructions (&optional (buffer (current-buffer)))
"Extracts processing instructions from BUFFER and returns a list of sexp representations in the style of xml-parse-*."
(save-excursion
(mapcar #'pi-str2s-exp
(mapcar #'(lambda (v)
(buffer-substring (aref v 1) (aref v 2)))
(--merge-pi-data (filter-xmltok-prolog buffer))))))
(cl-defun test/get-pis-from-file (file)
(with-temp-buffer
(insert-file-contents file)
(get-processing-instructions)))
(test/get-pis-from-file "~/some/xml/file.xml")
I'm not at all an Emacs Lisp expert and this isn't at all tested thoroughly, but it works for now! :)

How can I cycle through only those buffers which are in a given major mode (such as Python-mode ) ?

How can I cycle through only those buffers which are in a given major mode (such as Python-mode ) ?
Currently I am using C-X-Left/Right arrows, but these also show all sorts of irrelevant (i.e. non source code) buffers, any idea how can I restrict the buffer switching only to a specific type of buffer (with a given major mode) ?
I could not find something ready-made. However, it is not very hard to make the suitable commands.
(defun buffer-mode-alist ()
"Returns a list of (<buffer-name> . <major-mode>) pairs."
(let ((all-buffers (buffer-list))
(rv nil))
(while all-buffers
(let* ((this (car all-buffers))
(name (buffer-name this)))
(setq all-buffers (cdr all-buffers))
(when name
(setq rv (cons (cons name (with-current-buffer this major-mode)) rv)))))
rv))
(defun buffers-with-major-mode (the-major-mode)
(let ((buffer-alist (buffer-mode-alist))
(rv nil))
(while buffer-alist
(let ((this (car buffer-alist)))
(setq buffer-alist (cdr buffer-alist))
(if (eql (cdr this) the-major-mode)
(setq rv (cons (car this) rv)))))
(sort rv #'string<)))
(defun spin-buffers (buffer-list current)
(cond ((not (member current buffer-list)) buffer-list)
((string= current (car buffer-list)) buffer-list)
(t (spin-buffers (append (cdr buffer-list)
(list (car buffer-list)))
current))))
(defvar next-buffer-mode nil)
(defun choose-next-buffer-mode (mode)
"Ask for what major mode should be used as a selector for next-buffer-with-mode."
(interactive "aMajor Mode: ")
(setq next-buffer-mode mode))
(defun next-buffer-with-mode (set)
"Switches to the 'next' buffer with a given mode. If the mode is not set,
require it to be set, by calling choose-next-buffer-mode. If any prefix
argument is passed, also call choose-next-buffer-mode."
(interactive "P")
(when (or (not next-buffer-mode)
set)
(call-interactively 'choose-next-buffer-mode))
(let ((buffers (spin-buffers (buffers-with-major-mode next-buffer-mode)
(buffer-name))))
(when (cdr buffers)
(switch-to-buffer (cadr buffers)))))
(defun prev-buffer-with-mode (set)
"Switches to the 'previous' buffer with a given mode. If the mode is not set,
require it to be set, by calling choose-next-buffer-mode. If any prefix
argument is passed, also call choose-next-buffer-mode."
(interactive "P")
(when (or (not next-buffer-mode)
set)
(call-interactively 'choose-next-buffer-mode))
(let ((buffers (spin-buffers (buffers-with-major-mode next-buffer-mode)
(buffer-name))))
(when buffers
(switch-to-buffer (car (last buffers))))))

Display the bookmark name in the mode line of emacs

How can I display the name of a bookmark (from 'bookmark' or 'bookmark+') in the mode line of emacs, instead of the file name?
A slightly strange request, but here you go (works for files and dired buffers):
(defun show-bookmarks-mode-line ()
(interactive)
(let (bname text)
(and
(setq bname (if (eq major-mode 'dired-mode)
default-directory
(buffer-file-name)))
(setq bname (expand-file-name bname))
(setq text
(delq nil
(mapcar
(lambda (x)
(and (equal bname
(expand-file-name
(bookmark-get-filename x)))
(substring-no-properties (car x))))
bookmark-alist)))
(setq text
(mapconcat
#'identity
text
", "))
(let ((mode-line-buffer-identification
(propertize text 'face 'mode-line-buffer-id)))
(force-mode-line-update)
(sit-for 5))
(force-mode-line-update))))
Could you elaborate on why you need it?

In-Place Word/Symbol Dabbrev Expand

Here's my extension to dabbrev-expand to support sub-string expansion.It works as expected, as far as I know. However I would find it even more useful if it supported in-symbol expansion similar to the behaviour of mdabbrev, which, by the way, is incomplete in terms of symbol-character and case-adjustment support. The pattern argument to dabbrev-substring-search, however, is only the pattern before point but for in-place expansions we need the pattern after point aswell. Why isn't this pattern available in hippie/dabbrev-expand and is there a preferred way to query it?
(defun dabbrev-substring-search (pattern &optional reverse limit syntax-context)
"Expand dabbrev substring. See:
http://www.emacswiki.org/cgi-bin/wiki/HippieExpand#toc5"
(let ((result ())
(regpat (cond ((not hippie-epxand-dabbrev-as-symbol)
(concat (regexp-quote pattern) W*))
;; ((eq (char-syntax (aref pattern 0)) ?_)
;; (concat (regexp-quote pattern)
;; "\\(\\sw\\|\\s_\\)*"))
(t
(concat "\\(?:"
Y<
"\\(" "\\(?:\\sw\\|\\s_\\)+" "\\)"
"\\(" (regexp-quote pattern) "\\)"
"\\(" "\\(?:\\sw\\|\\s_\\)*" "\\)"
Y>
"\\)"
"\\|"
"\\(?:"
Y<
"\\(" "\\(?:\\sw\\|\\s_\\)*" "\\)"
"\\(" (regexp-quote pattern) "\\)"
"\\(" "\\(?:\\sw\\|\\s_\\)+" "\\)"
Y>
"\\)"
)))))
(while (and (not result)
(if reverse
(re-search-backward regpat limit t)
(re-search-forward regpat limit t)))
(setq result (buffer-substring-no-properties (save-excursion
(goto-char (match-beginning 0))
;;(skip-syntax-backward "w_")
(point))
(match-end 0)))
(if (he-string-member result he-tried-table t)
(setq result nil))) ; ignore if bad prefix or already in table
(when nil
(when result
(let* ((p (point))
(end3 (match-end 3))
(beg2 (match-end 2))
(end2 (match-end 2))
(dummy (message "%s %s %s" end3 beg2 end2))
(beg (- end3 beg2)) ;begin offset from point
(end (- end3 end2))) ;end offset from point
(setq dabbrev-substring-match-region (cons beg end))
(hictx-generic (- p beg) (- p end) nil 'match 3))))
result))
;; Use: (dabbrev-substring-search "he")
(defun try-expand-dabbrev-substring-visible (old)
"Like `try-expand-dabbrev' but for visible part of buffer."
(interactive "P")
(let ((old-fun (symbol-function 'he-dabbrev-search)))
(fset 'he-dabbrev-search (symbol-function 'dabbrev-substring-search))
(unwind-protect (try-expand-dabbrev-visible old)
(fset 'he-dabbrev-search old-fun))))
(defun try-expand-dabbrev-substring (old)
"Like `try-expand-dabbrev' but for substring match."
(interactive "P")
(let ((old-fun (symbol-function 'he-dabbrev-search)))
(fset 'he-dabbrev-search (symbol-function 'dabbrev-substring-search))
(unwind-protect (try-expand-dabbrev old)
(fset 'he-dabbrev-search old-fun))))
(defun try-expand-dabbrev-substring-all-buffers (old)
"Like `try-expand-dabbrev-all-buffers' but for substring match."
(interactive "P")
(let ((old-fun (symbol-function 'he-dabbrev-search)))
(fset 'he-dabbrev-search (symbol-function 'dabbrev-substring-search))
(unwind-protect (try-expand-dabbrev-all-buffers old)
(fset 'he-dabbrev-search old-fun))))
which is activated for example using
(setq hippie-expand-try-functions-list
(append
'(
try-expand-dabbrev-substring-visible
try-expand-dabbrev-substring
try-expand-dabbrev-substring-all-buffers)))
This might or might not help. Like ordinary dabbrev, it works with the text before point, but candidate matching can be substring, regexp, or fuzzy (various kinds), in addition to prefix. Icicles - Dynamic Abbreviation

In emacs, can I set up the *Messages* buffer so that it tails?

Basically I want the *Messages* buffer to always scroll to the bottom when a new message arrives.
Can I do that?
I found auto-revert-tail-mode but that works for buffers that are visiting files.
When I tried it in the Messages buffer, it popped an error:
auto-revert-tail-mode: This buffer is not visiting a file
For multiple frames you probably want:
(defadvice message (after message-tail activate)
"goto point max after a message"
(with-current-buffer "*Messages*"
(goto-char (point-max))
(walk-windows (lambda (window)
(if (string-equal (buffer-name (window-buffer window)) "*Messages*")
(set-window-point window (point-max))))
nil
t)))
Just put point at the end of the buffer M->. If you don't manually move it it will stay there -- IOW, you will always see the tail.
This code seems a bit overkill, but a the simple (goto-char (point-max)) wasn't working for me:
(defadvice message (after message-tail activate)
"goto point max after a message"
(with-current-buffer "*Messages*"
(goto-char (point-max))
(let ((windows (get-buffer-window-list (current-buffer) nil t)))
(while windows
(set-window-point (car windows) (point-max))
(setq windows (cdr windows))))))
Here's an implementation that uses the new advice style.
(defun message-buffer-goto-end-of-buffer (&rest args)
(let* ((win (get-buffer-window "*Messages*"))
(buf (and win (window-buffer win))))
(and win (not (equal (current-buffer) buf))
(set-window-point
win (with-current-buffer buf (point-max))))))
(advice-add 'message :after 'message-buffer-goto-end-of-buffer)
i run 23.3 and there were still way too many occasions where the built-in 'solution' and the orginal defadvice on the message function just didn't cut it, so i wrapped that code in a list / toggle / timer set up and it's working beautifully - no more frustration when debugging!
it's generic, so works on any buffer, although i only really use it for..
(toggle-buffer-tail "*Messages*" "on")
..hope it's useful to someone.
;alist of 'buffer-name / timer' items
(defvar buffer-tail-alist nil)
(defun buffer-tail (name)
"follow buffer tails"
(cond ((or (equal (buffer-name (current-buffer)) name)
(string-match "^ \\*Minibuf.*?\\*$" (buffer-name (current-buffer)))))
((get-buffer name)
(with-current-buffer (get-buffer name)
(goto-char (point-max))
(let ((windows (get-buffer-window-list (current-buffer) nil t)))
(while windows (set-window-point (car windows) (point-max))
(with-selected-window (car windows) (recenter -3)) (setq windows (cdr windows))))))))
(defun toggle-buffer-tail (name &optional force)
"toggle tailing of buffer NAME. when called non-interactively, a FORCE arg of 'on' or 'off' can be used to to ensure a given state for buffer NAME"
(interactive (list (cond ((if name name) (read-from-minibuffer
(concat "buffer name to tail"
(if buffer-tail-alist (concat " (" (caar buffer-tail-alist) ")") "") ": ")
(if buffer-tail-alist (caar buffer-tail-alist)) nil nil
(mapcar '(lambda (x) (car x)) buffer-tail-alist)
(if buffer-tail-alist (caar buffer-tail-alist)))) nil)))
(let ((toggle (cond (force force) ((assoc name buffer-tail-alist) "off") (t "on")) ))
(if (not (or (equal toggle "on") (equal toggle "off")))
(error "invalid 'force' arg. required 'on'/'off'")
(progn
(while (assoc name buffer-tail-alist)
(cancel-timer (cdr (assoc name buffer-tail-alist)))
(setq buffer-tail-alist (remove* name buffer-tail-alist :key 'car :test 'equal)))
(if (equal toggle "on")
(add-to-list 'buffer-tail-alist (cons name (run-at-time t 1 'buffer-tail name))))
(message "toggled 'tail buffer' for '%s' %s" name toggle)))))
edit: changed functionality to display tail at the bottom of the window
Here's an amendment over Peter's / Trey's solutions
(defun modi/messages-auto-tail (&rest _)
"Make *Messages* buffer auto-scroll to the end after each message."
(let* ((buf-name "*Messages*")
;; Create *Messages* buffer if it does not exist
(buf (get-buffer-create buf-name)))
;; Activate this advice only if the point is _not_ in the *Messages* buffer
;; to begin with. This condition is required; otherwise you will not be
;; able to use `isearch' and other stuff within the *Messages* buffer as
;; the point will keep moving to the end of buffer :P
(when (not (string= buf-name (buffer-name)))
;; Go to the end of buffer in all *Messages* buffer windows that are
;; *live* (`get-buffer-window-list' returns a list of only live windows).
(dolist (win (get-buffer-window-list buf-name nil :all-frames))
(with-selected-window win
(goto-char (point-max))))
;; Go to the end of the *Messages* buffer even if it is not in one of
;; the live windows.
(with-current-buffer buf
(goto-char (point-max))))))
(advice-add 'message :after #'modi/messages-auto-tail)