Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

204 lines
6.9 KiB

5 years ago
5 years ago
5 years ago
  1. ;;; language-id.el --- Library to work with programming language identifiers -*- lexical-binding: t -*-
  2. ;;
  3. ;; Author: Lassi Kortela <lassi@lassi.io>
  4. ;; URL: https://github.com/lassik/emacs-language-id
  5. ;; Package-Version: 0.12
  6. ;; Package-Commit: 2c99ce29b86fc635649f4e89723912dc1cc4f36c
  7. ;; Version: 0.12
  8. ;; Package-Requires: ((emacs "24") (cl-lib "0.5"))
  9. ;; Keywords: languages util
  10. ;; SPDX-License-Identifier: ISC
  11. ;;
  12. ;; This file is not part of GNU Emacs.
  13. ;;
  14. ;;; Commentary:
  15. ;;
  16. ;; language-id is a small, focused library that helps other Emacs
  17. ;; packages identify the programming languages and markup languages
  18. ;; used in Emacs buffers. The main point is that it contains an
  19. ;; evolving table of language definitions that doesn't need to be
  20. ;; replicated in other packages.
  21. ;;
  22. ;; Right now there is only one public function, `language-id-buffer'.
  23. ;; It looks at the major mode and other variables and returns the
  24. ;; language's GitHub Linguist identifier. We can add support for
  25. ;; other kinds of identifiers if there is demand.
  26. ;;
  27. ;; This library does not do any statistical text matching to guess the
  28. ;; language.
  29. ;;
  30. ;;; Code:
  31. (defvar language-id--file-name-extension nil
  32. "Internal variable for file name extension during lookup.")
  33. ;; <https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml>
  34. (defconst language-id--definitions
  35. '(
  36. ;;; Definitions that need special attention to precedence order.
  37. ;; json-mode is derived from javascript-mode.
  38. ("JSON"
  39. json-mode
  40. (web-mode (web-mode-content-type "json") (web-mode-engine "none")))
  41. ;; php-mode is derived from c-mode.
  42. ("PHP" php-mode)
  43. ;; scss-mode is derived from css-mode.
  44. ("SCSS" scss-mode)
  45. ;; terraform-mode is derived from hcl-mode.
  46. ("Terraform" terraform-mode)
  47. ;; TypeScript/TSX need to come before JavaScript/JSX because in
  48. ;; web-mode we can tell them apart by file name extension only.
  49. ;;
  50. ;; This implies that we inconsistently classify unsaved temp
  51. ;; buffers using TypeScript/TSX as JavaScript/JSX.
  52. ("TSX"
  53. typescript-tsx-mode
  54. (web-mode
  55. (web-mode-content-type "jsx")
  56. (web-mode-engine "none")
  57. (language-id--file-name-extension ".tsx")))
  58. ("TypeScript"
  59. typescript-mode
  60. (web-mode
  61. (web-mode-content-type "javascript")
  62. (web-mode-engine "none")
  63. (language-id--file-name-extension ".ts")))
  64. ;; ReScript needs to come before Reason because in reason-mode
  65. ;; we can tell them apart by file name extension only.
  66. ("ReScript"
  67. (reason-mode
  68. (language-id--file-name-extension ".res")))
  69. ("Reason" reason-mode)
  70. ;; vue-html-mode is derived from html-mode.
  71. ("Vue"
  72. vue-mode
  73. vue-html-mode
  74. (web-mode (web-mode-content-type "html") (web-mode-engine "vue")))
  75. ;;; The rest of the definitions are in alphabetical order.
  76. ("Assembly" asm-mode nasm-mode)
  77. ("ATS" ats-mode)
  78. ("Bazel" bazel-mode)
  79. ("BibTeX" bibtex-mode)
  80. ("C" c-mode)
  81. ("C#" csharp-mode)
  82. ("C++" c++-mode)
  83. ("Cabal Config" haskell-cabal-mode)
  84. ("Clojure" clojurescript-mode clojurec-mode clojure-mode)
  85. ("CMake" cmake-mode)
  86. ("Common Lisp" lisp-mode)
  87. ("Crystal" crystal-mode)
  88. ("CSS"
  89. css-mode
  90. (web-mode (web-mode-content-type "css") (web-mode-engine "none")))
  91. ("D" d-mode)
  92. ("Dart" dart-mode)
  93. ("Dhall" dhall-mode)
  94. ("Dockerfile" dockerfile-mode)
  95. ("Elixir" elixir-mode)
  96. ("Elm" elm-mode)
  97. ("Emacs Lisp" emacs-lisp-mode)
  98. ("Fish" fish-mode)
  99. ("GLSL" glsl-mode)
  100. ("Go" go-mode)
  101. ("GraphQL" graphql-mode)
  102. ("Haskell" haskell-mode)
  103. ("HCL" hcl-mode)
  104. ("HTML"
  105. html-helper-mode mhtml-mode html-mode nxhtml-mode
  106. (web-mode (web-mode-content-type "html") (web-mode-engine "none")))
  107. ("Java" java-mode)
  108. ("JavaScript"
  109. (js-mode (flow-minor-mode nil))
  110. (js2-mode (flow-minor-mode nil))
  111. (js3-mode (flow-minor-mode nil))
  112. (web-mode (web-mode-content-type "javascript") (web-mode-engine "none")))
  113. ("JSON"
  114. json-mode
  115. (web-mode (web-mode-content-type "json") (web-mode-engine "none")))
  116. ("Jsonnet" jsonnet-mode)
  117. ("JSX"
  118. js2-jsx-mode jsx-mode rjsx-mode react-mode
  119. (web-mode (web-mode-content-type "jsx") (web-mode-engine "none")))
  120. ("Kotlin" kotlin-mode)
  121. ("LaTeX" latex-mode)
  122. ("Less" less-css-mode)
  123. ("Literate Haskell" literate-haskell-mode)
  124. ("Lua" lua-mode)
  125. ("Markdown" gfm-mode markdown-mode)
  126. ("Nix" nix-mode)
  127. ("Objective-C" objc-mode)
  128. ("OCaml" caml-mode tuareg-mode)
  129. ("Perl" cperl-mode perl-mode)
  130. ("Protocol Buffer" protobuf-mode)
  131. ("PureScript" purescript-mode)
  132. ("Python" python-mode)
  133. ("R" ess-r-mode (ess-mode (ess-dialect "R")))
  134. ("Racket" racket-mode)
  135. ("Ruby" enh-ruby-mode ruby-mode)
  136. ("Rust" rust-mode rustic-mode)
  137. ("Scala" scala-mode)
  138. ("Scheme" scheme-mode)
  139. ("Shell" sh-mode)
  140. ("Solidity" solidity-mode)
  141. ("SQL" sql-mode)
  142. ("Swift" swift-mode swift3-mode)
  143. ("TOML" toml-mode conf-toml-mode)
  144. ("Verilog" verilog-mode)
  145. ("XML"
  146. nxml-mode xml-mode
  147. (web-mode (web-mode-content-type "xml") (web-mode-engine "none")))
  148. ("YAML" yaml-mode))
  149. "Internal table of programming language definitions.")
  150. (defun language-id--mode-match-p (mode)
  151. "Interal helper to match current buffer against MODE."
  152. (let ((mode (if (listp mode) mode (list mode))))
  153. (cl-destructuring-bind (wanted-major-mode . variables) mode
  154. (and (derived-mode-p wanted-major-mode)
  155. (cl-every
  156. (lambda (variable)
  157. (cl-destructuring-bind (symbol wanted-value) variable
  158. (equal wanted-value
  159. (if (boundp symbol) (symbol-value symbol) nil))))
  160. variables)))))
  161. (defun language-id-buffer ()
  162. "Get GitHub Linguist language name for current buffer.
  163. Return the name of the programming language or markup language
  164. used in the current buffer. The name is a string from the GitHub
  165. Linguist language list. The language is determined by looking at
  166. the active `major-mode'. Some major modes support more than one
  167. language. In that case minor modes and possibly other variables
  168. are consulted to disambiguate the language.
  169. In addition to the modes bundled with GNU Emacs, many third-party
  170. modes are recognized. No statistical text matching or other
  171. heuristics are used in detecting the language.
  172. The language definitions live inside the language-id library and
  173. are updated in new releases of the library.
  174. If the language is not unambiguously recognized, the function
  175. returns nil."
  176. (let ((language-id--file-name-extension
  177. (downcase (file-name-extension (or (buffer-file-name) "") t))))
  178. (cl-some (lambda (definition)
  179. (cl-destructuring-bind (language-id . modes) definition
  180. (when (cl-some #'language-id--mode-match-p modes)
  181. language-id)))
  182. language-id--definitions)))
  183. (provide 'language-id)
  184. ;;; language-id.el ends here