Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More Syntax Highlighting #1

Open
mikelococo opened this issue Feb 26, 2018 · 3 comments
Open

More Syntax Highlighting #1

mikelococo opened this issue Feb 26, 2018 · 3 comments

Comments

@mikelococo
Copy link

Thanks for writing this mode. I wrote some font-lock regular expressions to perform more granular syntax highlighting and thought I'd share them in case you or other users are interested. This covers every directive listed in the spec at https://www.chordpro.org/chordpro/ChordPro-Directives.html. Here's a screenshot:

screenshot from 2018-02-26 01-49-27

I'm not submitting this as a PR because it currently inherits from a bunch of random faces that I happened to have installed, so it's going to blow up for anyone but me in it's current condition. The real value is in the regular-expressions with groupings, though, and since everything has a defined face it's easy to tweak the inheritance.

;;; chordpro-init.el --- Customizations for chordpro-mode

;;; Commentary:
;; Expand the font-lock syntax highlighting in chordpro-mode.

;;; Code:
(require 'rx)

;; Regular expressions and faces for syntax highlighting
(defconst chordpro-comment-regexp
  ;; C-style comments, eg:
  ;;   # my comment
  (rx "#" (zero-or-more any)))
(defface chordpro-comment
  '((t :inherit font-lock-comment-delimiter-face))
  "Face for chordpro song chords."
  :group 'chordpro)

(defconst chordpro-title-regexp
  ;; Title directives, eg:
  ;;   {title: My Song}
  ;;   {subtitle: My subtitle}
  (rx (group "{")
      (group (or "title:" "t:" "subtitle:" "st:" "new_song:" "ns:"))
      (group (minimal-match (zero-or-more any)))
      (group "}")))
(defface chordpro-title
  '((t :inherit package-help-section-name))
  "Face for chordpro song titles and subtitles."
  :group 'chordpro)

(defconst chordpro-metadata-regexp
  ;; Metadata directives, eg:
  ;;   {artist: me}
  ;;   {capo: 3}
  ;;   {meta: my-custom-key my-value}
  (rx (group "{")
      (group (or "artist:" "composer:" "lyricist:"
                 "album:" "year:" "copyright:"
                 "key:" "time:" "tempo:" "duration:"
                 "meta:"))
      (group (minimal-match (zero-or-more any)))
      (group "}")))
(defface chordpro-metadata
  '((t :inherit js2-private-member))
  "Face for chordpro song directives related to song metadata."
  :group 'chordpro)

(defconst chordpro-font-and-output-regexp
  ;; Font and output directives, eg:
  ;;   {new_page}
  ;;   {columns: 2}
  (rx (group "{")
      (group (or "textfont:" "textsize:" "textcolour:"
                 "chordfont:" "chordsize:" "chordcolour:"
                 "tabfont:" "tabsize:" "tabcolour:"
                 "new_page" "np"
                 "new_physical_page" "npp"
                 "column_break" "cb"
                 "grid" "g" "no_grid" "ng"
                 "titles:"
                 "columns:" "col:"))
      (group (minimal-match (zero-or-more any)))
      (group "}")))
(defface chordpro-font-and-output
  '((t :inherit shadow))
  "Face for chordpro song directives related to fonts and output."
  :group 'chordpro)

(defconst chordpro-verse-directive-regexp
  ;; Directives to start or end a verse, eg:
  ;;   {start_of_verse}
  ;;   {end_of_verse}
  (rx (group "{")
      (group (or "start_of_verse" "end_of_verse"))
      (group "}")))
(defface chordpro-verse-directive
  '((t :inherit anzu-match-1))
  "Face for chordpro song directives mark the start of end of a verse."
  :group 'chordpro)

(defconst chordpro-chorus-directive-regexp
  ;; Directives to start or end a chorus, eg:
  ;;   {start_of_chorus}
  ;;   {eoc}
  (rx (group "{")
      (group (or "start_of_chorus" "soc" "end_of_chorus" "eoc" "chorus"))
      (group "}")))
(defface chordpro-chorus-directive
  '((t :inherit ivy-minibuffer-match-face-2))
  "Face for chordpro song directives mark the start of end of a chorus."
  :group 'chordpro)

(defconst chordpro-tab-or-grid-directive-regexp
  ;; Directives to start or end a chorus, eg:
  ;;   {start_of_chorus}
  ;;   {eoc}
  (rx (group "{")
      (group (or "start_of_tab" "sot" "end_of_tab" "eot"
                 "start_of_grid" "end_of_grid"))
      (group "}")))
(defface chordpro-tab-or-grid-directive
  '((t :inherit tooltip))
  "Face for chordpro song directives mark the start of end of a tab or grid."
  :group 'chordpro)

(defconst chordpro-builtin-directive-regexp
  ;; Other built-In directives, eg:
  ;;   {start_of_chorus}
  ;;   {comment: hello}
  (rx (group "{")
      (group (or "comment:" "c:" "comment_italic:" "ci:" "comment_box:" "cb:"
                 "image:"
                 "define:" "chord:"))
      (group (minimal-match (zero-or-more any)))
      (group "}")))
(defface chordpro-builtin-directive-name
  '((t :inherit font-lock-comment-face))
  "Face for chordpro built-in directive names with no special highlighting."
  :group 'chordpro)
(defface chordpro-builtin-directive-value
  '((t :inherit font-lock-doc-face))
  "Face for chordpro built-in directive values with no special highlighting."
  :group 'chordpro)
(defface chordpro-directive-delimiter
  '((t :inherit font-lock-constant-face))
  "Face for chordpro song directive curly bracket delimiters."
  :group 'chordpro)

(defconst chordpro-extension-directive-regexp
  ;; Extension directives, eg:
  ;;   {x_boolean_extension}
  ;;   {x_string_extension: hello}
  (rx (group "{")
      (group "x_"
             (minimal-match (one-or-more any))
             (zero-or-one ":"))
      (group (minimal-match (zero-or-more any)))
      (group "}")))
(defface chordpro-extension-directive-name
  '((t :inherit chordpro-builtin-directive-name))
  "Face for chordpro song directive names that conform to the extension spec."
  :group 'chordpro)
(defface chordpro-extension-directive-value
  '((t :inherit chordpro-extension-directive-value))
  "Face for chordpro song directive values that conform to the extension spec."
  :group 'chordpro)

(defconst chordpro-unrecognized-directive-regexp
  ;; Invalid directives, eg:
  ;;   {invalid_example_directive}
  (rx "{" (minimal-match (one-or-more any)) "}" ))
(defface chordpro-unrecognized-directive
  '((t :inherit isearch-fail))
  "Face for chordpro song directives that appear to be invalid."
  :group 'chordpro)

(defconst chordpro-chord-regexp
  ;; Chords, eg:
  ;;   [G]
  ;;   [Am7]
  (rx (group "[" )
      (group (minimal-match (zero-or-more any)))
      (group "]")))
(defface chordpro-chord
  '((t :inherit flycheck-fringe-error))
  "Face for chordpro song chords."
  :group 'chordpro)
(defface chordpro-chord-delimiter
  '((t :inherit flycheck-error-list-warning))
  "Face for chordpro song chord square bracket delimiters."
  :group 'chordpro)

;; Font lock settings for syntax highlighting
(add-hook 'chordpro-mode-hook
          (lambda ()
            (font-lock-add-keywords nil
                                    ;; Note that the backtickery in this section
                                    ;; is extremely fiddly:
                                    ;;     - Backtick the whole list to quote it
                                    ;;       but allow selective unquoting.
                                    ;;     - Comma each regex to eval it
                                    ;;     - Single-quote each face, also to
                                    ;;       eval it. Maybe commas would work?
                                    ;;       I cargo-culted this from:
                                    ;;       https://emacs.stackexchange.com/a/3587
                                    `((,chordpro-comment-regexp
                                       0 'chordpro-comment)

                                      (,chordpro-title-regexp
                                       0 'chordpro-title)
                                      (,chordpro-metadata-regexp
                                       0 'chordpro-metadata)
                                      (,chordpro-font-and-output-regexp
                                       0 'chordpro-font-and-output)

                                      (,chordpro-verse-directive-regexp
                                       0 'chordpro-verse-directive)
                                      (,chordpro-chorus-directive-regexp
                                       0 'chordpro-chorus-directive)
                                      (,chordpro-tab-or-grid-directive-regexp
                                       0 'chordpro-tab-or-grid-directive)
                                      (,chordpro-builtin-directive-regexp
                                       (1 'chordpro-directive-delimiter)
                                       (2 'chordpro-builtin-directive-name)
                                       (3 'chordpro-builtin-directive-value)
                                       (4 'chordpro-directive-delimiter))
                                      (,chordpro-extension-directive-regexp
                                       (1 'chordpro-directive-delimiter)
                                       (2 'chordpro-extension-directive-name)
                                       (3 'chordpro-directive-value)
                                       (4 'chordpro-directive-delimiter))

                                      ;; Will match any directive, must be
                                      ;; preceded but other directive
                                      ;; highlighers.
                                      (,chordpro-unrecognized-directive-regexp
                                       0 'chordpro-unrecognized-directive)

                                      (,chordpro-chord-regexp
                                       (1 'chordpro-chord-delimiter)
                                       (2 'chordpro-chord)
                                       (3 'chordpro-chord-delimiter))
                                      ))))

(add-to-list 'auto-mode-alist '("\\.crd$" . chordpro-mode))
;;; chordpro-init.el ends here
@josephmturner
Copy link

josephmturner commented Apr 9, 2023

Hi @mikelococo! So that your work might be incorporated in chordpro-mode, would you please give permission to use this code under MIT/GPL/AGPL? A fork of this repository lives here. Please also see #5.

Thanks for sharing!

@mikelococo
Copy link
Author

@josephmturner Apologies for the late response on this, I don't watch my github notifications as I should. If it's still relevant, I'm happy to have the changes above or any adaptation/derivative thereof be licensed under a license of your choosing. Indeed I'm happy to release them to the public domain or perform copyright assignment. I hope my latency hasn't caused any great waste of effort. Thanks for taking over maintainership.

@josephmturner
Copy link

@mikelococo Thank you!! I don't sweat the legal stuff - I just wanted to make sure to follow your wishes regarding your work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants