Why doesn't font-lock-fontify-buffer work from elisp when it works from the minibuffer? - emacs

So I'm hacking up some elisp to test a web service, and I'm running into trouble with syntax highlighting. I'm using url-retrieve-synchronously to get an HTTP response, then editing the text to get down to just the XML I need to see. Unfortunately, syntax highlighting doesn't work in the returned buffer, even though I've set it to nxml-mode and used "font-lock-fontify-buffer" in the script. However, if I do "M-x font-lock-fontify-buffer", the highlighting works as I would expect. Is there some difference between using it in elisp and from inside emacs?
Here are the relevant parts of the script I'm putting together. I admit up front that this is the first elisp scripting I've ever done, and I'm probably doing things in a ludicrously incorrect manner, but it's all worked thus far.
(defun modality-http-request (url args request-type)
(let ((url-request-method request-type)
(url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded")))
(url-request-data
(mapconcat (lambda (arg)
(concat (url-hexify-string (car arg))
"="
(url-hexify-string (cdr arg))))
args
"&")))
(url-retrieve-synchronously url)))
(defun modality-http-get (url args)
(modality-http-request url args "GET"))
(defun modality-http-post (url args)
(modality-http-request url args "POST"))
(defun test-modality (test)
(interactive "s\Test: ")
(let ((buffer (modality-http-get (concat (get-modality-path) test) nil)))
(set-buffer buffer)
(setq modality-beginning (point))
(forward-paragraph)
(next-line)
(beginning-of-line)
(setq modality-end (point))
(delete-region modality-beginning modality-end)
(bf-pretty-print-xml-region)
(switch-to-buffer buffer)
(font-lock-fontify-buffer)))
(defun bf-pretty-print-xml-region ()
"Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this. The function inserts linebreaks to separate tags that have
nothing but whitespace between them. It then indents the markup
by using nxml's indentation rules."
(interactive "r")
(save-excursion
(nxml-mode)
(goto-char (point-min))
(while (search-forward-regexp "\>[ \\t]*\<" nil t)
(backward-char) (insert "\n"))
(indent-region (point-min) (point-max))
))

URL uses temporary/internal buffers (recognized by the fact that their name starts with a space). They're plain normal, but some functions treat them specially: font-lock will not be activated, and the buffer will usually not be shown to the user (e.g. C-x b TAB will not show those buffers).
So either rename the buffer before enabling font-lock, or copy the text you need into another buffer whose name doesn't start with a space.

Related

ggtags find-definition/reference with IDO interface

I dont like default ggtags interface around ggtags-find-definition/reference/file. I managed to get ggtags-find-file work with IDO, but ggtags-find-definition is a lot harder problem.
Is there some package which can do it? If not, how to make one?
NOTE: I want to be able to browse found definitions/references in fuzzy minibuffer, not whole new buffer (and window).
Normally, I would suggest ido-completing-read-plus (formerly ido-ubiquitous). It makes almost every command that uses completing-read use ido-completing-read instead. However, there is one major case where it doesn't work well: when the completion candidates are generated by a function. This is the case for ggtags-completion-table, which is how ggtags generates its completion candidates.
The solution is to define your own ggtags-completing-read-function that expands the candidates before passing to ido-completing-read. Note: the reason why ido-completing-read (and in turn ido-completing-read-plus) doesn't allow this is because it might use a ton of memory and CPU, and may freeze the UI. You will probably need to tune this to make it acceptable if you have a large number of completion candidates. Also note that most ggtags commands work with the symbol at point; it seems like you generally just give a prefix arg (C-u) to make it prompt for the symbol.
(defun jpk/ggtags-completing-read (&rest args)
(apply #'ido-completing-read
(car args)
(all-completions "" ggtags-completion-table)
(cddr args)))
(setq ggtags-completing-read-function #'jpk/ggtags-completing-read)
Assuming that you ran ggtags-find-definition and it found results and put them in the buffer *ggtags-global*, this function will extract the filenames and line numbers and let you use IDO to pick the one you want.
(defun ido-goto-grep-results (grep-buffer prompt)
(interactive)
(let (candidates result filename dirname line)
(with-current-buffer grep-buffer
(setq dirname default-directory)
(save-excursion
(save-match-data
(goto-char (point-min))
(forward-line 4)
(while (re-search-forward "^\\(.+\\):\\([0-9]+\\):" nil 'noerror)
(push (concat (match-string 1) ":" (match-string 2))
candidates)))))
(setq result (split-string (ido-completing-read prompt candidates nil t) ":"))
(setq filename (car result))
(setq line (string-to-number (cadr result)))
(find-file-other-window (expand-file-name filename dirname))
(goto-char (point-min))
(forward-line (1- line))))
(ido-goto-grep-results "*ggtags-global*" "Jump to definition: ")
This is pretty rough. You probably want to make your own find-definition command that runs ggtags-find-definition and ido-goto-grep-results at once. Somehow you need to only get the actual results and not the "Global found N definitions..." line (better regexp, narrow the ggtags buffer, or some other way).

Auto-escaping yanked strings in emacs

I apparently have a powerful itch this weekend to add a ton of functionality to my Emacs environment. I can do some basics on my own, and hunt down other stuff, but I haven't been able to find a solution to this (and am not good enough at Lisp to do it on my own).
I frequently work with strings of HTML, and sometimes if I move them from one block to another (or one language to another) strings are broken where they aren't escaped. So, I want a function that does something like this:
(defun smart-yank-in-string()
(if (stringp) ; Check if the point is in a string
; Check if the region created from the point to the end of the yank ends the string
; (and there is more yank left that isn't ";")
; Escape quotes for those locations recursively by prepending \
; Insert result into buffer # mark
))
Any clever ideas? I think it involves using kill-new to stash a variable and walk through it, but I'm not conversant enough in elisp to solve it.
Next yank should insert the escaped string:
(defun escape-doublequotes-at-car-of-kill-ring ()
"Escape doublequotes in car of kill-ring "
(interactive)
(with-temp-buffer
(insert (car kill-ring))
(goto-char (point-min))
(while (search-forward "\"" nil t 1)
(replace-match "\\\\\""))
(kill-new (buffer-substring-no-properties (point-min) (point-max)))))
Here is an alternative
(defun my-yank()
(interactive)
(if (nth 3 (syntax-ppss)) ;; Checks if inside a string
(insert-for-yank (replace-regexp-in-string "[\\\"]"
"\\\\\\&"
(current-kill 0)
t))
(call-interactively 'yank)))
The command when invoked checks if the point is in a string, if so it escapes the yanked text otherwise it yanks normally. One disadvantage is that you cannot use yank-pop after yanking inside a string.
Maybe you could do it as follow (guaranteed 100% non-functional code ahead):
(defun my-kill-quoted-string (start end)
"Like kill-region but takes of unquoting/requoting."
(interactive "r")
(let ((str (buffer-extract-substring start end)))
(if (nth 3 (syntax-ppss))
;; Unquote according to mode and context. E.g. we should unquote " and things like that in HTML.
(setq str (replace-regexp-in-string "\\\\\"" "\"" str)))
(put-text-property 0 (length str) 'yank-handler
(list (lambda (str)
(if (not (nth 3 (syntax-ppss)))
(insert str)
;; Requote according to mode and context.
(insert (replace-regexp-in-string "[\\\"]" "\\\\\\&" str))))))
(kill-new str)))

Highlight a name throughout an Emacs buffer

I am starting to learn Emacs Lisp, and as a first project I would like to improve the fortran mode in Emacs. I would like to mark the name of a sub routine in the buffer, and then press a shortcut key. To bring up a buffer with all lines in the given source where the name of the subroutine is mentioned.
I found that I can get the marked text using:
(defun get-selected-text (beg end)
(interactive
(if (use-region-p)
(list (region-beginning) (region-end))
(list nil nil)))
(message "%s" (if (and beg end)
(buffer-substring-no-properties beg end) "")))
and can store the line numbers of the subroutines using:
(defun get-line-numbers (str)
(interactive "sEnter string: ")
(save-excursion
(goto-char 0)
(let (( sok 1) (list nil) pp)
(while sok
(setq pp (search-forward str nil t))
(if pp (push (line-number-at-pos pp) list)
(setq sok nil)))
(message "%s" list))))
I would now like to open a new buffer similar to when I use Ctrl-x Ctrl-b to execute list-buffers and then display each line number, together with the text on the line, and the user can select a given line, and press Enter to goto the given line in the original buffer..
Just wanted to show you my version of occur-dwim.
I remember spending some time to find out about the regexp-history variable.
The first function is similar to your get-selected-text.
(defun region-str-or-symbol ()
"Return the contents of region or current symbol."
(if (region-active-p)
(buffer-substring-no-properties
(region-beginning)
(region-end))
(thing-at-point 'symbol)))
(defun occur-dwim ()
"Call `occur' with a sane default."
(interactive)
(push (region-str-or-symbol) regexp-history)
(call-interactively 'occur))
To display the list-buffer you use get-buffer-create and clear it with erase-buffer (it might be that it already extisted).
To output the lines you search in the current buffer save the line in a string and put it into the list buffer via with-current-buffer and insert.
To make return special on the text or to make it clickable put a text-property with a local keymap on it.
With this guide you should be able to find everything you need in the elisp-manual.
Regarding your code, you get the beginning and end of the current region with (interactive "r"). Therewith you also get the error message if there is no active region.

Disable auto-fill-mode locally (or un fill-paragraph) with emacs

I use M-q for fill-paragraph, can I do the un-fill-paragraph in auto-fill-mode?
With org mode, I sometimes enter [[Very long HTML][Name with spaces]], and for the 'Name with spaces' the auto-fill mode break the whole line based on the inserted space, which makes it very ugly.
Is there a command something like un-fill-paragraph? Or, is there a way disable auto-fill-mode temporarily/locally?
Emacs does not record what was your line before calling fill-paragraph. So the only thing you can do is C-_ which runs the command undo. It can undo your fill-paragraph command but only if it is the preceding command call.
If you want to put a multi-line paragraph on one line you could do like this :
Select the region
C-M-% C-q C-j RET SPACE RET !
Xah Lee has updated his code since monotux's answer, and I refactored it somewhat for readability:
(defun my-toggle-fill-paragraph ()
;; Based on http://xahlee.org/emacs/modernization_fill-paragraph.html
"Fill or unfill the current paragraph, depending upon the current line length.
When there is a text selection, act on the region.
See `fill-paragraph' and `fill-region'."
(interactive)
;; We set a property 'currently-filled-p on this command's symbol
;; (i.e. on 'my-toggle-fill-paragraph), thus avoiding the need to
;; create a variable for remembering the current fill state.
(save-excursion
(let* ((deactivate-mark nil)
(line-length (- (line-end-position) (line-beginning-position)))
(currently-filled (if (eq last-command this-command)
(get this-command 'currently-filled-p)
(< line-length fill-column)))
(fill-column (if currently-filled
most-positive-fixnum
fill-column)))
(if (region-active-p)
(fill-region (region-beginning) (region-end))
(fill-paragraph))
(put this-command 'currently-filled-p (not currently-filled)))))
To remake a long line out of a paragraph in Org mode, I gave myself a new command. Here is the associated Emacs Lisp code:
(defun fp-unfill-paragraph (&optional justify region)
(interactive (progn
(barf-if-buffer-read-only)
(list (if current-prefix-arg 'full) t)))
(interactive)
(let ((fill-column 100000))
(fill-paragraph justify region)))
(global-set-key "\C-ceu" 'fp-unfill-paragraph)
Of course, you adjust the command keybinding as you see fit!
I use the following snippet to fill and un-fill paragraphs (using only M-q), it is really, really handy. I borrowed it from Xah Lee, but removed some comments and whitespace in order to make it fit in here. The link in the first comment goes to his original code.
;; http://xahlee.org/emacs/modernization_fill-paragraph.html
(defun compact-uncompact-block ()
"Remove or add line endings on the current block of text.
This is similar to a toggle for fill-paragraph and unfill-paragraph
When there is a text selection, act on the region.
When in text mode, a paragraph is considered a block. When in programing
language mode, the block defined by between empty lines.
Todo: The programing language behavior is currently not done.
Right now, the code uses fill* functions, so does not work or work well
in programing lang modes. A proper implementation to compact is replacing
newline chars by space when the newline char is not inside string.
"
(interactive)
(let (bds currentLineCharCount currentStateIsCompact
(bigFillColumnVal 4333999) (deactivate-mark nil))
(save-excursion
(setq currentLineCharCount
(progn
(setq bds (bounds-of-thing-at-point 'line))
(length (buffer-substring-no-properties (car bds) (cdr bds)))))
(setq currentStateIsCompact
(if (eq last-command this-command)
(get this-command 'stateIsCompact-p)
(if (> currentLineCharCount fill-column) t nil)))
(if (and transient-mark-mode mark-active)
(if currentStateIsCompact
(fill-region (region-beginning) (region-end))
(let ((fill-column bigFillColumnVal))
(fill-region (region-beginning) (region-end)))
)
(if currentStateIsCompact
(fill-paragraph nil)
(let ((fill-column bigFillColumnVal))
(fill-paragraph nil))))
(put this-command 'stateIsCompact-p
(if currentStateIsCompact
nil t)))))
(global-set-key (kbd "M-q") 'compact-uncompact-block)

Emacs Lisp buffer not running font lock mode until opened by user

My problem is I am opening a buffer using (set-buffer (find-tag-noselect (current-word))) and then I try to copy some text out of that buffer. The text that I get back has only the properties (fontified nil). find-tag-noselect automatically opens the buffer found in the TAGS file but it seems it does not run the font lock mode over it. When I manually switch to this buffer after it has been opened and then run the function again when it copies the text it has all the correct text properties attached. So what do I need to do to have this buffer completely initialized so that the correct syntax highlighting will be copied in?
(defvar newline-string "
")
(defun get-initial-indent-regexp-python()
"Gets the initial amount of spaces for the function we are looking at, does not account for tabs"
(concat "^" (get-current-indent-string) (concat "[^ #" newline-string "]")))
(defun get-end-of-function-python(spaces-regex)
"Gets the point at the end of a python block"
(save-excursion
(forward-line 1)
(while (and (not (looking-at spaces-regex)) (equal (forward-line 1) 0)))
(point)))
(defun get-point-at-end-of-function ()
"This might be better served checking the major mode."
(setq extension (file-name-extension (buffer-file-name)))
(if (equal extension "py")
(get-end-of-function-python (get-initial-indent-regexp-python))))
(defun inline-function ()
"Must change to overlays, be able to toggle visibility"
(interactive)
(let (text indent-string)
; clean all overlays without attached buffer
(save-excursion
(set-buffer (find-tag-noselect (current-word)))
(setq text (buffer-substring (point) (get-point-at-end-of-function))))
(setq text (concat newline-string text))
(save-excursion
(move-end-of-line nil)
(let (overlay)
(setq overlay (make-overlay (point) (+ (point) 1) (current-buffer)))
(overlay-put overlay 'display text)
(setq inline-func-overlays (cons overlay inline-func-overlays))))))
What's happening is that font-lock is done on-the-fly, so only the displayed parts of the buffer get "fontified". If you want/need to overrule this optimization, you need different functions depending on the circumstance (depending on how font-lock happens to be configured). We should add a new font-lock-ensure-fontified function for that, but in the mean time, you can take ps-print-.el as an example:
(defun ps-print-ensure-fontified (start end)
(cond ((and (boundp 'jit-lock-mode) (symbol-value 'jit-lock-mode))
(jit-lock-fontify-now start end))
((and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode))
(lazy-lock-fontify-region start end))))
I'm not exactly sure what you're trying to do, but set-buffer does not display the buffer, so its effect ends when the current command terminates. It's generally useful only for temporary buffer switches inside a function and I guess this is the reason it doesn't run font-lock on the buffer. When you manually go to the buffer you're probably using a different function - switch-to-buffer.
Try explicitly calling 'font-lock-fontify-buffer'.