From c19565c101dd0419483a89c14c35d99123574dad Mon Sep 17 00:00:00 2001 From: Howard Ding Date: Sat, 15 Mar 2014 22:18:09 -0500 Subject: [PATCH] Rename function to have chordpro- prefix Make chord regexp save the actual chord without the brackets Add function for deleting chord without killing it Add functionality to use dropdown lists to pick chord to insert/replace from chords already in the document. Remap middle buttons to do more useful things --- README.md | 13 ++++++++++- chordpro-mode.el | 59 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 52216d2..7d166d5 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ extension for such files): Now when you visit a .pro file you should automatically get chordpro-mode. +Some of the functions use dropdown-list.el, which can be installed +with package-list-packages in modern emacs. If you don't have this +installed they'll just do nothing. + ## Use ## ### Keyboard ### @@ -40,6 +44,8 @@ All of the keyboard commands use the Ctrl-c prefix. * Ctrl-c i : Insert a chord at the point. You'll be prompted for the chord name in the minibuffer. The brackets will automatically be inserted, space trimmed, and the chord capitalized. +* Ctrl-c l : Insert a chord at the point, chosen from a dropdown list + of chords already in the document. * Ctrl-c w : Kills the current chord. The current chord is one containing the point - because of the way emacs works this means that this command doesn't do what you want if the cursor is on the @@ -48,6 +54,8 @@ All of the keyboard commands use the Ctrl-c prefix. * Ctrl-c z : Kills the next chord. Finds the next chord after the point and kills it. This one works if you are on the opening [, or if you are between chords. +* Ctrl-c r : Replace the current chord with one chosen from a dropdown + list of chords already in the document. * Ctrl-c c : Copy the current chord * Ctrl-c x : Copy the next chord * Ctrl-c h : Insert a chordpro comment @@ -63,7 +71,10 @@ experiments. All of them have corresponding keyboard commands (whether specific to this mode or standard emacs commands). * Ctrl-mouse-1 : Kills current chord -* Ctrl-mouse-2 : Yanks last kill (this is prone to change, as you can typically do this with a normal mouse-2) +* Ctrl-mouse-2 : Insert a chord at the point, chosen from a dropdown list + of chords already in the document. Note that unfortunately as currently + implemented the mouse click can only bring up the menu - you still need + to use the keyboard to perform the selection. * Ctrl-mouse-3 : Kills next chord * Shift-mouse-1 : Copies current chord * Shift-mouse-2 : Insert chord diff --git a/chordpro-mode.el b/chordpro-mode.el index 005103d..ed8546e 100644 --- a/chordpro-mode.el +++ b/chordpro-mode.el @@ -1,4 +1,5 @@ (require 'derived) +(require 'dropdown-list nil t) (defvar chordpro-font-lock-defaults '((("\\(\\[[^]]*\\]\\)" . font-lock-string-face) @@ -23,16 +24,18 @@ Special commands: (define-key chordpro-mode-map "\C-ch" 'chordpro-insert-chorus) (define-key chordpro-mode-map "\C-ct" 'chordpro-insert-title) (define-key chordpro-mode-map "\C-cs" 'chordpro-insert-subtitle) +(define-key chordpro-mode-map "\C-cl" 'chordpro-choose-insert-chord) +(define-key chordpro-mode-map "\C-cr" 'chordpro-choose-replace-current-chord) (define-key chordpro-mode-map [C-down-mouse-1] 'mouse-set-point) (define-key chordpro-mode-map [C-mouse-1] 'chordpro-kill-current-chord) (define-key chordpro-mode-map [C-down-mouse-2] 'mouse-set-point) -(define-key chordpro-mode-map [C-mouse-2] 'yank) +(define-key chordpro-mode-map [C-mouse-2] 'chordpro-mouse-choose-insert-chord) (define-key chordpro-mode-map [C-down-mouse-3] 'mouse-set-point) (define-key chordpro-mode-map [C-mouse-3] 'chordpro-kill-next-chord) (define-key chordpro-mode-map [S-down-mouse-1] 'mouse-set-point) (define-key chordpro-mode-map [S-mouse-1] 'chordpro-copy-current-chord) (define-key chordpro-mode-map [S-down-mouse-2] 'mouse-set-point) -(define-key chordpro-mode-map [S-mouse-2] 'mouse-insert-chord) +(define-key chordpro-mode-map [S-mouse-2] 'chordpro-mouse-insert-chord) (define-key chordpro-mode-map [S-down-mouse-3] 'mouse-set-point) (define-key chordpro-mode-map [S-mouse-3] 'chordpro-copy-next-chord) @@ -41,17 +44,60 @@ Special commands: (interactive "*MChord:") (insert "[" (chordpro-normalize-chord chord) "]")) -(defun mouse-insert-chord (event chord) +(defun chordpro-mouse-insert-chord (event chord) "Prompt for and insert chord at point, performing some normalization." (interactive "@e\nMChord:") (insert "[" (chordpro-normalize-chord chord) "]")) +(defun chordpro-choose-insert-chord () + "Insert a chord chosen from a dropdown menu that contains all chords +already in the document." + (interactive) + (when (featurep 'dropdown-list) + (let* ((choices (chordpro-buffer-chord-list)) + (selection (dropdown-list choices))) + (when selection + (chordpro-insert-chord (nth selection choices)))))) + +(defun chordpro-mouse-choose-insert-chord (event) + "Insert a chord chosen from a dropdown menu that contains all chords +already in the document." + (interactive "@e") + (when (featurep 'dropdown-list) + (let* ((choices (chordpro-buffer-chord-list)) + (selection (dropdown-list choices))) + (when selection + (chordpro-insert-chord (nth selection choices)))))) + +;;;This could be done more efficiently, but for most usages +;;;it shouldn't be a problem to just scan the whole document each time +(defun chordpro-buffer-chord-list () + "Return a list of the chords currently used in the document." + (interactive) + (let ((chords nil)) + (save-excursion + (save-match-data + (goto-char (point-min)) + (while (re-search-forward chordpro-chord-regexp nil t) + (add-to-list 'chords (match-string 1))))) + (sort chords 'string<))) + +(defun chordpro-choose-replace-current-chord () + "Replace the current chord with one chosen from a dropdown list" + (interactive) + (when (featurep 'dropdown-list) + (let* ((choices (chordpro-buffer-chord-list)) + (selection (dropdown-list choices))) + (when selection + (chordpro-delete-current-chord) + (chordpro-insert-chord (nth selection choices)))))) + (defun chordpro-normalize-chord (chord) "Trim whitespace, capitalize first letter of chord." (capitalize (replace-regexp-in-string "\\s " "" chord))) (defvar chordpro-chord-regexp - "\\[[^][]*\\]" + "\\[\\([^][]*\\)\\]" "Regexp for matching a chord without regard for the point.") (defun chordpro-kill-next-chord () @@ -76,6 +122,11 @@ Special commands: (interactive) (operate-on-current-chord 'kill-region)) +(defun chordpro-delete-current-chord () + "Delete the chord surrounding the point, if there is one." + (interactive) + (operate-on-current-chord 'delete-region)) + (defun chordpro-copy-current-chord () "Copy the chord surrounding the point, if there is one." (interactive)