Grande solução. Mas eu concordo em usar o ffap
, que faz parte do GNU Emacs. %código%
resolve muitos problemas sutis, expande as variáveis de ambiente e também captura
URLs.
No entanto, ffap
não pode ser usado facilmente a partir do próprio Lisp. Minha reimplementação de ffap
é baseada em buttonize-buffer
e ffap-next-regexp
. A parte difícil era trabalhar o bug mencionado abaixo, e obter o ponto de início do arquivo ou URL, que ffap-guesser
não fornece.
O analisador varre o buffer atual e imprime os detalhes no buffer de mensagens; lá você pode ver quais strings são adivinhadas como arquivos, que combinam e quais são abotoados.
(defun buttonize-buffer ()
"Turn all file paths and URLs into buttons."
(interactive)
(require 'ffap)
(deactivate-mark)
(let (token guess beg end reached bound len)
(save-excursion
(setq reached (point-min))
(goto-char (point-min))
(while (re-search-forward ffap-next-regexp nil t)
;; There seems to be a bug in ffap, Emacs 23.3.1: 'ffap-file-at-point'
;; enters endless loop when the string at point is "//".
(setq token (ffap-string-at-point))
(unless (string= "//" (substring token 0 2))
;; Note that 'ffap-next-regexp' only finds some "indicator string" for a
;; file or URL. 'ffap-string-at-point' blows this up into a token.
(save-excursion
(beginning-of-line)
(when (search-forward token (point-at-eol) t)
(setq beg (match-beginning 0)
end (match-end 0)
reached end))
)
(message "Found token %s at (%d-%d)" token beg (- end 1))
;; Now let 'ffap-guesser' identify the actual file path or URL at
;; point.
(when (setq guess (ffap-guesser))
(message " Guessing %s" guess)
(save-excursion
(beginning-of-line)
(when (search-forward guess (point-at-eol) t)
(setq len (length guess) end (point) beg (- end len))
;; Finally we found something worth buttonizing. It shall have
;; at least 2 chars, however.
(message " Matched at (%d-%d]" beg (- end 1))
(unless (or (< (length guess) 2))
(message " Buttonize!")
(make-button beg end :type 'find-file-button))
)
)
)
;; Continue one character after the guess, or the original token.
(goto-char (max reached end))
(message "Continuing at %d" (point))
)
)
)
)
)
Para instalar permanentemente a função:
(add-hook 'find-file-hook 'buttonize-buffer)
Uma solução melhor é "buffers de botão preguiçoso":
(defun buttonize-current-buffer-on-idle (&optional secs)
"Idle-timer (see \[run-with-idle-timer]) that buttonizes filenames and URLs.
SECS defaults to 60 seconds idle time."
(interactive)
(run-with-idle-timer (or secs 60) t 'buttonize-buffer))
(add-hook 'after-init-hook 'buttonize-current-buffer-on-idle)