Add button with dynamic menu to emacs's modeline? - emacs

I'm making my own minor mode for emacs. Now I want to add button to modeline. Click on this button must сause pop-up menu appear. The items of this menu depend on user's actions. I know that there is a way to add a function button to modeline with `minor-mode-alist', but I have no idea how to make dynamic menu.

Ok. Solution founded.:)
First: define some keymap:
(defconst my-mode-line-map
(let ((map (make-sparse-keymap)))
(define-key map [mode-line down-mouse-1]
(make-sparse-keymap))
map))
Second: append list with propertized string to modeline:
(setq global-mode-string
(append global-mode-string
(list
(propertize string-name
'local-map my-mode-line-map
'mouse-face 'mode-line-highlight))))
Third: Now you can add items with
(define-key my-mode-line-map
(vconcat [mode-line down-mouse-1]
(list some_generated_id_for_future_use))
(cons name function))
...and remove with
(define-key my-mode-line-map
(vconcat [mode-line down-mouse-1]
(list id_of_button_that_u_gave_when_add))
nil)

I found more proper way:
When you define minor mode, you can specify :lighter param
(define-minor-mode my-minor-mode
"docstring"
nil
:lighter (:eval (format "%s%.5s" "#" "some code if you want dynamic label"))
;or just string :lighter "static string"
:keymap my-minor-mode-map
... ... ... rest of code ....
then you can use easymenu:
(require 'easymenu)
(easy-menu-define my-minor-mode-menu
my-minor-mode-map
"Menu for my-minor-mode"
'("some text"
"-")) ;separator
; and then add menu items with easy-menu-add-item and remove with easy-menu-remove-item
; it's nothing hard. Read the docs ;)
This menu will be added to global menu-bar and it will pop up if you click on auto added(cause you specified :lighter param) minor-mode button on modeline.

Related

Counsel-rg omit long maching line

I utilize the counsel-rg to search the pattern of "~[a-z]+~", it displays the desired results but omit long matching line:
How could enable it to get long-matching-line displayed?
Here is an example usage:
;; counsel-rg (&optional initial-input initial-directory extra-rg-args rg-prompt)
(defun ugt-counsel-rg ()
"Add initial search text into minibuffer."
(interactive)
(let ((initial-input "^\\*+ ") ;; Search only org headers
(initial-directory "~/org")
(extra-rg-args "--max-columns 300") ;; <== THIS
(rg-prompt "rg: Search org file headers (narrow with =S-SPC= or =!keyword=: "))
(counsel-rg initial-input
initial-directory
extra-rg-args
rg-prompt)))
(global-set-key (kbd "s-u") 'ugt-counsel-rg)

Emacs helm completion: how to turn off persistent-help_line?

I'd like to use helm as a drop-in replacement for display-completion-list.
The only issue is that it displays this line on top, which I don't want:
C-z: I don't want this line here (keeping session).
Here's the code to illustrate:
(helm :sources `((name . "Do you have?")
(candidates . ("Red Leicester"
"Tilsit"
"Caerphilly"
"Bel Paese"
"Red Windsor"
"Stilton"))
(action . identity)
(persistent-help . "I don't want this line here"))
:buffer "*cheese shop*")
I've tried setting persistent-help to nil, or not setting it at all, but it
still appears. How can I turn it off?
The attribute helm-persistent-help-string comes with the library helm-plugin. If you do not load it you get no help string. If you need to load helm-plugin for some reason you can disable the function helm-persistent-help-string afterwards by:
(defadvice helm-persistent-help-string (around avoid-help-message activate)
"Avoid help message"
)
If you want to remove the gray header line completely you can do:
(defadvice helm-display-mode-line (after undisplay-header activate)
(setq header-line-format nil))
With defadvice you change the behavior of helm globally.
If you want to change helm-display-mode-line just temporarily for the execution of your helm command you could use:
(defmacro save-function (func &rest body)
"Save the definition of func in symbol ad-func and execute body like `progn'
Afterwards the old definition of func is restored."
`(let ((ad-func (if (autoloadp (symbol-function ',func)) (autoload-do-load (symbol-function ',func)) (symbol-function ',func))))
(unwind-protect
(progn
,#body
)
(fset ',func ad-func)
)))
(save-function helm-display-mode-line
(fset 'helm-display-mode-line '(lambda (source)
(apply ad-func (list source))
(setq header-line-format nil)))
(helm :sources `((name . "Do you have?")
(candidates . ("Red Leicester"
"Tilsit"
"Caerphilly"
"Bel Paese"
"Red Windsor"
"Stilton"))
(action . identity)
(persistent-help . "I don't want this line here"))
:buffer "*cheese shop*"))
(Note, that stuff like cl-flet does not work this way.)

How to disable a mode specified key-binding in Emacs [duplicate]

I have globally assigned C-c/ to ace-jump-mode but reftex-mode (a minor mode for citations used with AucTeX) overrides this key with some function I never use.
I tried local-unset-key but it only unbinds keys from the current major mode's map.
How do I remove C-c/ from reftex-mode-map without making changes to reftex.el?
You can change an existing key map using define-key. By passing nil as the function to call, the key will become unbound. I guess that you should be able to do something like:
(define-key reftex-mode-map "\C-c/" nil)
Of course, you should do this in some kind of hook, for example:
(defun my-reftex-hook ()
(define-key reftex-mode-map "\C-c/" nil))
(add-hook 'reftex-mode-hook 'my-reftex-hook)
You can use following command:
(define-key reftex-mode-map "\C-c/" nil)
to unmap this function from C-c /... But reftex-mode should be loaded, so reftex-mode-map will available for modification
This is how I do it. It could be improved, though.
(defun get-key-combo (key)
"Just return the key combo entered by the user"
(interactive "kKey combo: ")
key)
(defun keymap-unset-key (key keymap)
"Remove binding of KEY in a keymap
KEY is a string or vector representing a sequence of keystrokes."
(interactive
(list (call-interactively #'get-key-combo)
(completing-read "Which map: " minor-mode-map-alist nil t)))
(let ((map (rest (assoc (intern keymap) minor-mode-map-alist))))
(when map
(define-key map key nil)
(message "%s unbound for %s" key keymap))))
;;
;; Then use it interativly
;; Or like this:
(keymap-unset-key '[C-M-left] "paredit-mode")
..
..

how to dynamically define a menu item - what is the thing in square braces?

Not clear on some fundamental syntax here. define-key accepts a set of inputs, one of which is inside square braces. What is that construct? How can I dynamically generate what goes inside the square braces?
In the simple case, I can display a one-item menu like this:
(flet ((ok (&optional p1 &rest args) t))
(setq menu-1 (make-sparse-keymap "Title"))
(define-key menu-1 [menu-1-ok-event]
`(menu-item "OK"
ok
:keys ""
:visible t
:enable t))
(x-popup-menu t menu-1))
I can insert additional menu items like this:
(flet ((ok (&optional p1 &rest args) t))
(setq menu-1 (make-sparse-keymap "Title"))
(define-key menu-1 [menu-1-event-ok]
`(menu-item "OK"
ok
:keys ""
:visible t
:enable t))
(define-key menu-1 [menu-1-event-1]
`(menu-item "This is line 1"
nil
:keys ""
:visible t
:enable t))
(x-popup-menu t menu-1))
But what if I want to dynamically generate the thing inside square braces? What if I want something like this:
(while (< n 5)
(define-key menu-1 [(dynamic-thing n)]
`(menu-item (format "This is line %d" n)
nil
:keys ""
:visible t
:enable t)))
I tried
(define-key menu-1 [(intern (format "menu-1-event-%d" n))]
...
..but that did not work. The result is always "intern". ???
What are the square braces? The syntax is unfamiliar to me.
These are vectors. [foo bar] is syntactic sugar for (quote (vector foo bar)); it's a literal. To construct a vector where the elements need to be evaluated, use the vector built-in function explicitly; it works like list.
(define-key menu-1 (vector (format "menu-1-event-%d" n)) …
The chapter on menu keymaps may help as well.

Highlighting correctly in an emacs major mode

I am developing an emacs major mode for a language (aka mydsl). However, using the techniques on xahlee's site doesn't seem to be working for some reason (possibly older emacs dialect..)
The key issues I am fighting with are (1) highlighting comments is not working and (2), the use of regexp-opt lines is not working.
I've reviewed the GNU manual and looked over cc-mode and elisp mode... those are significantly more complicated than I need.
;;;Standard # to newline comment
;;;Eventually should also have %% to %% multiline block comments
(defun mydsl-comment-dwim (arg)
"comment or uncomment"
(interactive "*P")
(require 'newcomment)
(let
((deactivate-mark nil)
(comment-start "#")
(comment-end "")
comment-dwim arg)))
(defvar mydsl-events
'("reservedword1"
"reservedword2"))
(defvar mydsl-keywords
'("other-keyword" "another-keyword"))
;;Highlight various elements
(setq mydsl-hilite
'(
; stuff between "
("\"\\.\\*\\?" . font-lock-string-face)
; : , ; { } => # $ = are all special elements
(":\\|,\\|;\\|{\\|}\\|=>\\|#\\|$\\|=" . font-lock-keyword-face)
( ,(regexp-opt mydsl-keywords 'words) . font-lock-builtin-face)
( ,(regexp-opt mydsl-events 'words) . font-lock-constant-face)
))
(defvar mydsl-tab-width nil "Width of a tab for MYDSL mode")
(define-derived-mode mydsl-mode fundamental-mode
"MYDSL mode is a major mode for editing MYDSL files"
;Recommended by manual
(kill-all-local-variables)
(setq mode-name "MYDSL script")
(setq font-lock-defaults '((mydsl-hilite)))
(if (null mydsl-tab-width)
(setq tab-width mydsl-tab-width)
(setq tab-width default-tab-width)
)
;Comment definitions
(define-key mydsl-mode-map [remap comment-dwim] 'mydsl-comment-dwim)
(modify-syntax-entry ?# "< b" mydsl-mode-syntax-table)
(modify-syntax-entry ?\n "> b" mydsl-mode-syntax-table)
;;A gnu-correct program will have some sort of hook call here.
)
(provide 'mydsl-mode)
You have a couple of syntactic problems in your code, but you got it nearly correct. Here's my edited version which appears to do the right thing for a buffer in mydsl-mode:
; No changes to the simple vars
(defvar mydsl-events
'("reservedword1"
"reservedword2"))
(defvar mydsl-keywords
'("other-keyword" "another-keyword"))
;; I'd probably put in a default that you want, as opposed to nil
(defvar mydsl-tab-width nil "Width of a tab for MYDSL mode")
;; Two small edits.
;; First is to put an extra set of parens () around the list
;; which is the format that font-lock-defaults wants
;; Second, you used ' (quote) at the outermost level where you wanted ` (backquote)
;; you were very close
(defvar mydsl-font-lock-defaults
`((
;; stuff between "
("\"\\.\\*\\?" . font-lock-string-face)
;; ; : , ; { } => # $ = are all special elements
(":\\|,\\|;\\|{\\|}\\|=>\\|#\\|$\\|=" . font-lock-keyword-face)
( ,(regexp-opt mydsl-keywords 'words) . font-lock-builtin-face)
( ,(regexp-opt mydsl-events 'words) . font-lock-constant-face)
)))
(define-derived-mode mydsl-mode fundamental-mode "MYDSL script"
"MYDSL mode is a major mode for editing MYDSL files"
;; fundamental-mode kills all local variables, no need to do it again
(setq mode-name "MYDSL script")
;; you again used quote when you had '((mydsl-hilite))
;; I just updated the variable to have the proper nesting (as noted above)
;; and use the value directly here
(setq font-lock-defaults mydsl-font-lock-defaults)
;; when there's an override, use it
;; otherwise it gets the default value
(when mydsl-tab-width
(setq tab-width mydsl-tab-width))
;; for comments
;; overriding these vars gets you what (I think) you want
;; they're made buffer local when you set them
(setq comment-start "#")
(setq comment-end "")
(modify-syntax-entry ?# "< b" mydsl-mode-syntax-table)
(modify-syntax-entry ?\n "> b" mydsl-mode-syntax-table)
;;A gnu-correct program will have some sort of hook call here.
)
(provide 'mydsl-mode)