Klimi's new dotfiles with stow.
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.

3111 lines
125 KiB

4 years ago
  1. ;;; csharp-mode.el --- C# mode derived mode
  2. ;; Author : Dylan R. E. Moonfire (original)
  3. ;; Maintainer : Jostein Kjønigsen <jostein@gmail.com>
  4. ;; Created : Feburary 2005
  5. ;; Modified : 2018
  6. ;; Version : 0.9.2
  7. ;; Package-Version: 20190717.1024
  8. ;; Keywords : c# languages oop mode
  9. ;; X-URL : https://github.com/josteink/csharp-mode
  10. ;; Last-saved : 2018-Jul-08
  11. ;;
  12. ;; This program is free software; you can redistribute it and/or modify
  13. ;; it under the terms of the GNU General Public License as published by
  14. ;; the Free Software Foundation; either version 2 of the License, or
  15. ;; (at your option) any later version.
  16. ;;
  17. ;; This program is distributed in the hope that it will be useful,
  18. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. ;; GNU General Public License for more details.
  21. ;;
  22. ;; You should have received a copy of the GNU General Public License
  23. ;; along with this program; see the file COPYING. If not, write to
  24. ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  25. ;; Boston, MA 02111-1307, USA.
  26. ;;; Commentary:
  27. ;;
  28. ;; This is a major mode for editing C# code. It performs automatic
  29. ;; indentation of C# syntax; font locking; and integration with
  30. ;; imenu.el.
  31. ;;
  32. ;; csharp-mode requires CC Mode 5.30 or later. It works with
  33. ;; cc-mode 5.31.3, which is current at this time.
  34. ;;
  35. ;; Features:
  36. ;;
  37. ;; - font-lock and indent of C# syntax including:
  38. ;; all c# keywords and major syntax
  39. ;; attributes that decorate methods, classes, fields, properties
  40. ;; enum types
  41. ;; #if/#endif #region/#endregion
  42. ;; instance initializers
  43. ;; anonymous functions and methods
  44. ;; verbatim literal strings (those that begin with @)
  45. ;; generics
  46. ;;
  47. ;; - automagic code-doc generation when you type three slashes.
  48. ;;
  49. ;; - compatible with electric-pair-mode for intelligent insertion
  50. ;; of matched braces, quotes, etc.
  51. ;;
  52. ;; - imenu integration - generates an index of namespaces, classes,
  53. ;; interfaces, methods, and properties for easy navigation within
  54. ;; the buffer.
  55. ;;
  56. ;; Installation instructions
  57. ;; --------------------------------
  58. ;;
  59. ;; Put csharp-mode.el somewhere in your load path, optionally byte-compile
  60. ;; it, and add the following to your .emacs file:
  61. ;;
  62. ;; (autoload 'csharp-mode "csharp-mode" "Major mode for editing C# code." t)
  63. ;; (setq auto-mode-alist
  64. ;; (append '(("\\.cs$" . csharp-mode)) auto-mode-alist))
  65. ;;
  66. ;;
  67. ;; Optionally, define and register a mode-hook function. To do so, use
  68. ;; something like this in your .emacs file:
  69. ;;
  70. ;; (defun my-csharp-mode-fn ()
  71. ;; "function that runs when csharp-mode is initialized for a buffer."
  72. ;; (turn-on-auto-revert-mode)
  73. ;; (setq indent-tabs-mode nil)
  74. ;; ...insert more code here...
  75. ;; ...including any custom key bindings you might want ...
  76. ;; )
  77. ;; (add-hook 'csharp-mode-hook 'my-csharp-mode-fn t)
  78. ;;
  79. ;;
  80. ;; General
  81. ;; ----------------------------
  82. ;;
  83. ;; Mostly C# mode will "just work." Use `describe-mode' to see the
  84. ;; default keybindings and the highlights of the mode.
  85. ;;
  86. ;;
  87. ;; imenu integration
  88. ;; -----------------------------
  89. ;;
  90. ;; This should just work. For those who don't know what imenu is, it
  91. ;; allows navigation to different points within the file from an
  92. ;; "Index" menu, in the window's menubar. csharp-mode computes the
  93. ;; menu containing the namespaces, classes, methods, and so on, in the
  94. ;; buffer. This happens at the time the file is loaded; for large
  95. ;; files it takes a bit of time to complete the scan. If you don't
  96. ;; want this capability, set `csharp-want-imenu' to nil.
  97. ;;
  98. ;;
  99. ;;; Known Bugs:
  100. ;;
  101. ;; The imenu scan is text-based and naive. For example, if you
  102. ;; intersperse comments between the name of a class/method/namespace,
  103. ;; and the curly brace, the scan will not recognize the thing being
  104. ;; declared. This is fixable - would need to extract the buffer
  105. ;; substring then remove comments before doing the regexp checks - but
  106. ;; it would make the scan much slower. Also, the scan doesn't deal
  107. ;; with preproc symbol definitions and #if/#else. Those things are
  108. ;; invisible to the scanner csharp-mode uses to build the imenu menu.
  109. ;;
  110. ;; Leading identifiers are no longer being fontified, for some reason.
  111. ;; See matchers-before. (Not sure this is still a problem - 19 may
  112. ;; 2011 DPC)
  113. ;;
  114. ;; Method names with a preceding attribute are not fontified.
  115. ;;
  116. ;; The symbol followng #if is not fontified. It should be treated like
  117. ;; define and get font-lock-variable-name-face .
  118. ;;
  119. ;; This code doesn't seem to work when you compile it, then
  120. ;; load/require in the emacs file. You will get an error (error
  121. ;; "`c-lang-defconst' must be used in a file") which happens because
  122. ;; cc-mode doesn't think it is in a buffer while loading directly
  123. ;; from the init. However, if you call it based on a file extension,
  124. ;; it works properly. Interestingly enough, this doesn't happen if
  125. ;; you don't byte-compile cc-mode.
  126. ;;
  127. ;;
  128. ;;
  129. ;; Todo:
  130. ;;
  131. ;; imenu should scan for and find delegates and events, in addition
  132. ;; to the classes, structs, properties and methods it does currently.
  133. ;;
  134. ;; Get csharp-mode.el accepted as part of the emacs standard distribution.
  135. ;; Must contact monnier at iro.umontreal.ca to make this happen.
  136. ;;
  137. ;; Add refactoring capabilities?
  138. ;; - extract as method - extract a block of code into a method
  139. ;; - extract as Func<> - extract a block of code into an Action<T>
  140. ;;
  141. ;; More code-gen power:
  142. ;; - interface implementation - I think would require csharp-shell
  143. ;;
  144. ;;
  145. ;; Acknowledgements:
  146. ;;
  147. ;; Thanks to Alan Mackenzie and Stefan Monnier for answering questions
  148. ;; and making suggestions. And to Trey Jackson for sharing his
  149. ;; knowledge of emacs lisp.
  150. ;;
  151. ;;
  152. ;;; Versions:
  153. ;;
  154. ;; 0.1.0 - Initial release.
  155. ;; 0.2.0 - Fixed the identification on the "enum" keyword.
  156. ;; - Fixed the font-lock on the "base" keyword
  157. ;; 0.3.0 - Added a regex to fontify attributes. It isn't the
  158. ;; the best method, but it handles single-like attributes
  159. ;; well.
  160. ;; - Got "super" not to fontify as a keyword.
  161. ;; - Got extending classes and interfaces to fontify as something.
  162. ;; 0.4.0 - Removed the attribute matching because it broke more than
  163. ;; it fixed.
  164. ;; - Corrected a bug with namespace not being properly identified
  165. ;; and treating the class level as an inner object, which screwed
  166. ;; up formatting.
  167. ;; - Added "partial" to the keywords.
  168. ;; 0.5.0 - Found bugs with compiled cc-mode and loading from init files.
  169. ;; - Updated the eval-when-compile to code to let the mode be
  170. ;; compiled.
  171. ;; 0.6.0 - Added the c-filter-ops patch for 5.31.1 which made that
  172. ;; function in cc-langs.el unavailable.
  173. ;; - Added a csharp-lineup-region for indention #region and
  174. ;; #endregion block differently.
  175. ;; 0.7.0 - Added autoload so update-directory-autoloads works
  176. ;; (Thank you, Nikolaj Schumacher)
  177. ;; - Fontified the entire #region and #endregion lines.
  178. ;; - Initial work to get get, set, add, remove font-locked.
  179. ;; 0.7.1 - Added option to indent #if/endif with code
  180. ;; - Fixed c-opt-cpp-prefix defn (it must not include the BOL
  181. ;; char (^).
  182. ;; - proper fontification and indent of classes that inherit
  183. ;; (previously the colon was confusing the parser)
  184. ;; - reclassified namespace as a block beginner
  185. ;; - removed $ as a legal symbol char - not legal in C#.
  186. ;; - added struct to c-class-decl-kwds so indent is correct
  187. ;; within a struct.
  188. ;; 0.7.2 - Added automatic codedoc insertion.
  189. ;; 0.7.3 - Instance initializers (new Type { ... } ) and
  190. ;; (new Type() { ...} ) are now indented properly.
  191. ;; - proper fontification and indent of enums as brace-list-*,
  192. ;; including special treatment for enums that explicitly
  193. ;; inherit from an int type. Previously the colon was
  194. ;; confusing the parser.
  195. ;; - proper fontification of verbatim literal strings,
  196. ;; including those that end in slash. This edge case was not
  197. ;; handled at all before; it is now handled correctly.
  198. ;; - code cleanup and organization; removed the formfeed.
  199. ;; - intelligent curly-brace insertion with
  200. ;; `csharp-insert-open-brace'
  201. ;; 0.7.4 - added a C# style
  202. ;; - using is now a keyword and gets fontified correctly
  203. ;; - fixed a bug that had crept into the codedoc insertion.
  204. ;; 0.7.5 - now fontify namespaces in the using statements. This is
  205. ;; done in the csharp value for c-basic-matchers-before .
  206. ;; - also fontify the name following namespace decl.
  207. ;; This is done in the csharp value for c-basic-matchers-after .
  208. ;; - turn on recognition of generic types. They are now
  209. ;; fontified correctly.
  210. ;; - <> are now treated as syntactic parens and can be jumped
  211. ;; over with c-forward-sexp.
  212. ;; - Constructors are now fontified.
  213. ;; - Field/Prop names inside object initializers are now fontified.
  214. ;;
  215. ;; 0.7.7 - relocate running c-run-mode-hooks to the end of
  216. ;; csharp-mode, to allow user to modify key bindings in a
  217. ;; hook if he doesn't like the defaults.
  218. ;;
  219. ;; 0.7.8 - redefine csharp-log to insert timestamp.
  220. ;; - Fix byte-compile errors on emacs 23.2 ? Why was
  221. ;; c-filter-ops duplicated here? What was the purpose of its
  222. ;; presence here, I am not clear.
  223. ;;
  224. ;; 0.8.0 - include flymake magic into this module.
  225. ;; - include yasnippet integration
  226. ;;
  227. ;; 0.8.2 2011 April DPC
  228. ;; - small tweaks; now set a one-time bool for flymake installation
  229. ;; - some doc updates on flymake
  230. ;;
  231. ;; 0.8.3 2011 May 17 DPC
  232. ;; - better help on csharp-mode
  233. ;; - csharp-move-* functions for manual navigation.
  234. ;; - imenu integration for menu-driven navigation - navigate to
  235. ;; named methods, classes, etc.
  236. ;; - adjusted the flymake regexp to handle output from fxcopcmd,
  237. ;; and extended the help to provide examples how to use this.
  238. ;;
  239. ;; 0.8.4 DPC 2011 May 18
  240. ;; - fix a basic bug in the `csharp-yasnippet-fixup' fn.
  241. ;;
  242. ;; 0.8.5 DPC 2011 May 21
  243. ;; - imenu: correctly parse Properties that are part of an
  244. ;; explicitly specified interface. Probably need to do this
  245. ;; for methods, too.
  246. ;; - fontify the optional alias before namespace in a using (import).
  247. ;; - Tweak open-curly magic insertion for object initializers.
  248. ;; - better fontification of variables and references
  249. ;; - "sealed" is now fontified as a keyword
  250. ;; - imenu: correctly index ctors that call this or base.
  251. ;; - imenu: correctly index Extension methods (this System.Enum e)
  252. ;; - imenu: correctly scan method params tagged with out, ref, params
  253. ;; - imenu scan: now handle curlies within strings.
  254. ;; - imenu: split menus now have better labels, are sorted correctly.
  255. ;;
  256. ;; 0.8.6 DPC 2011 May ??
  257. ;; - extern keyword
  258. ;;
  259. ;; 0.8.7 2014 November 29
  260. ;; - Fix broken cl-dependency in emacs24.4 and defadvice for tooltips.
  261. ;;
  262. ;; 0.8.8 2014 December 3
  263. ;; - Fix broken byte-compile.
  264. ;; - Add extra C# keywords.
  265. ;; - Call prog-mode hooks.
  266. ;;
  267. ;; 0.8.9 2015 March 15
  268. ;; - (Re)add compilation-mode support for msbuild and xbuild.
  269. ;;
  270. ;; 0.8.10 2015 May 31th
  271. ;; - Imenu: Correctly handle support for default-values in paramlist.
  272. ;;
  273. ;; 0.8.11 2015 November 21st
  274. ;; - Make mode a derived mode. Improve evil-support.
  275. ;; - Add support for devenv compilation-output.
  276. ;; - Fix all runtime warnings
  277. ;; - Fix error with string-values in #region directives.
  278. ;;
  279. ;; 0.8.12 2016 January 6th
  280. ;; - Various fixes and improvements for imenu indexing.
  281. ;;
  282. ;; 0.9.0 2016 September 9th
  283. ;; - Fix issues with compilation-mode and lines with arrays.
  284. ;; - Fontification of compiler directives.
  285. ;; - Much faster, completely rewritten imenu-implementation.
  286. ;; - Fix indentation issues.
  287. ;; - Fix Emacs-25 related bugs.
  288. ;; - Cleaned up dead code.
  289. ;;
  290. ;; 0.9.1 2017
  291. ;; - Fix indentation for generic type-initializers.
  292. ;; - Fix fontification of using and namespace-statements with
  293. ;; underscores in them.
  294. ;; - Fixes for indentation for many kinds of type-initializers.
  295. ;;
  296. ;; 0.9.2 2018 July
  297. ;; - Try to fix some breakage introduced by changes in Emacs 27.
  298. ;;
  299. ;;; Code:
  300. (require 'cc-mode)
  301. (require 'cc-fonts)
  302. (require 'cl-lib)
  303. ;; prevent warnings like
  304. ;; csharp-mode.el:4134:21:Warning: reference to free variable
  305. ;; `compilation-error-regexp-alist-alist'
  306. (require 'compile)
  307. ;; Work around emacs bug#23053
  308. (eval-when-compile
  309. (require 'cc-langs))
  310. ;; Work around emacs bug#18845
  311. (eval-when-compile
  312. (when (and (= emacs-major-version 24) (>= emacs-minor-version 4))
  313. (require 'cl)))
  314. (require 'imenu)
  315. ;; ==================================================================
  316. ;; c# upfront stuff
  317. ;; ==================================================================
  318. ;; This is a copy of the function in cc-mode which is used to handle the
  319. ;; eval-when-compile which is needed during other times.
  320. ;;
  321. ;; NB: I think this is needed to satisfy requirements when this module
  322. ;; calls `c-lang-defconst'. (DPC)
  323. ;; (defun c-filter-ops (ops opgroup-filter op-filter &optional xlate)
  324. ;; ;; See cc-langs.el, a direct copy.
  325. ;; (unless (listp (car-safe ops))
  326. ;; (setq ops (list ops)))
  327. ;; (cond ((eq opgroup-filter t)
  328. ;; (setq opgroup-filter (lambda (opgroup) t)))
  329. ;; ((not (functionp opgroup-filter))
  330. ;; (setq opgroup-filter `(lambda (opgroup)
  331. ;; (memq opgroup ',opgroup-filter)))))
  332. ;; (cond ((eq op-filter t)
  333. ;; (setq op-filter (lambda (op) t)))
  334. ;; ((stringp op-filter)
  335. ;; (setq op-filter `(lambda (op)
  336. ;; (string-match ,op-filter op)))))
  337. ;; (unless xlate
  338. ;; (setq xlate 'identity))
  339. ;; (c-with-syntax-table (c-lang-const c-mode-syntax-table)
  340. ;; (delete-duplicates
  341. ;; (mapcan (lambda (opgroup)
  342. ;; (when (if (symbolp (car opgroup))
  343. ;; (when (funcall opgroup-filter (car opgroup))
  344. ;; (setq opgroup (cdr opgroup))
  345. ;; t)
  346. ;; t)
  347. ;; (mapcan (lambda (op)
  348. ;; (when (funcall op-filter op)
  349. ;; (let ((res (funcall xlate op)))
  350. ;; (if (listp res) res (list res)))))
  351. ;; opgroup)))
  352. ;; ops)
  353. ;; :test 'equal)))
  354. (defgroup csharp nil
  355. "Major mode for editing C# code."
  356. :group 'prog-mode)
  357. ;; Custom variables
  358. ;; ensure all are defined before using ...;
  359. (defcustom csharp-mode-hook nil
  360. "*Hook called by `csharp-mode'."
  361. :type 'hook
  362. :group 'csharp)
  363. ;; The following fn allows this:
  364. ;; (csharp-log 3 "scan result...'%s'" state)
  365. (defcustom csharp-log-level 0
  366. "The current log level for CSharp-mode-specific operations.
  367. This is used in particular by the verbatim-literal
  368. string scanning.
  369. Most other csharp functions are not instrumented.
  370. 0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG, 4 = SHUTUP ALREADY."
  371. :type 'integer
  372. :group 'csharp)
  373. (defcustom csharp-want-imenu t
  374. "*Whether to generate a buffer index via imenu for C# buffers."
  375. :type 'boolean :group 'csharp)
  376. ;; These are only required at compile time to get the sources for the
  377. ;; language constants. (The load of cc-fonts and the font-lock
  378. ;; related constants could additionally be put inside an
  379. ;; (eval-after-load "font-lock" ...) but then some trickery is
  380. ;; necessary to get them compiled.)
  381. (eval-when-compile
  382. (let ((load-path
  383. (if (and (boundp 'byte-compile-dest-file)
  384. (stringp byte-compile-dest-file))
  385. (cons (file-name-directory byte-compile-dest-file) load-path)
  386. load-path)))
  387. (load "cc-mode" nil t)
  388. (load "cc-fonts" nil t)
  389. (load "cc-langs" nil t)))
  390. (eval-and-compile
  391. ;; ==================================================================
  392. ;; constants used in this module
  393. ;; ==================================================================
  394. (defconst csharp-type-initializer-statement-re
  395. (concat
  396. "\\<new[ \t\n\r\f\v]+"
  397. "\\([[:alpha:]_][[:alnum:]_<>\\.]*\\)")
  398. "Regexp that captures a type-initializer statement in C#")
  399. (defconst csharp-enum-decl-re
  400. (concat
  401. "\\<enum[ \t\n\r\f\v]+"
  402. "\\([[:alpha:]_][[:alnum:]_]*\\)"
  403. "[ \t\n\r\f\v]*"
  404. "\\(:[ \t\n\r\f\v]*"
  405. "\\("
  406. (c-make-keywords-re nil
  407. (list "sbyte" "byte" "short" "ushort" "int" "uint" "long" "ulong"))
  408. "\\)"
  409. "\\)?")
  410. "Regex that captures an enum declaration in C#")
  411. ;; ==================================================================
  412. ;; Make our mode known to the language constant system. Use Java
  413. ;; mode as the fallback for the constants we don't change here.
  414. ;; This needs to be done also at compile time since the language
  415. ;; constants are evaluated then.
  416. (c-add-language 'csharp-mode 'java-mode))
  417. ;; ==================================================================
  418. ;; end of c# upfront stuff
  419. ;; ==================================================================
  420. ;; ==================================================================
  421. ;; csharp-mode utility and feature defuns
  422. ;; ==================================================================
  423. (defun csharp--at-vsemi-p (&optional pos)
  424. "Determines if there is a virtual semicolon at POS or point.
  425. It returns t if at a position where a virtual-semicolon is.
  426. Otherwise nil.
  427. This is the C# version of the function. It gets set into
  428. the variable `c-at-vsemi-p-fn'.
  429. A vsemi is a cc-mode concept implying the end of a statement,
  430. where no actual end-of-statement signifier character ( semicolon,
  431. close-brace) appears. The concept is used to allow proper
  432. indenting of blocks of code: Where a vsemi appears, the following
  433. line will not indent further.
  434. A vsemi appears in 2 cases in C#:
  435. - after an attribute that decorates a class, method, field, or
  436. property.
  437. - in an object initializer, before the open-curly?
  438. An example of the former is [WebMethod] or [XmlElement].
  439. Providing this function allows the indenting in `csharp-mode'
  440. to work properly with code that includes attributes."
  441. (save-excursion
  442. (let ((pos-or-point (progn (if pos (goto-char pos)) (point))))
  443. (cond
  444. ;; before open curly in object initializer. new Foo* { }
  445. ((and (looking-back
  446. (concat "\\<new[ \t\n\f\v\r]+"
  447. ;; typename
  448. "\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*"
  449. "[A-Za-z_][[:alnum:]]*"
  450. ;; simplified generic constraint.
  451. ;; handles generic sub-types.
  452. ;; { is optional because otherwise initializers with
  453. ;; bracket on same line will indent wrongly.
  454. "\\(?:<[[:alnum:], <>]+>[ \t\n\f\v\r]*{?\\)?"
  455. ;; optional array-specifier
  456. "\\(?:\\[\\]\\)?"
  457. ;; spacing
  458. "[\ t\n\f\v\r]*") nil)
  459. (looking-at "[ \t\n\f\v\r]*{"))
  460. t)
  461. ;; put a vsemi after an attribute, as with
  462. ;; [XmlElement]
  463. ;; Except when the attribute is used within a line of code, as
  464. ;; specifying something for a parameter.
  465. ((c-safe (backward-sexp) t)
  466. (cond
  467. ((re-search-forward
  468. (concat
  469. "\\(\\["
  470. "[ \t\n\r\f\v]*"
  471. "\\("
  472. "\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*"
  473. "[A-Za-z_][[:alnum:]]*"
  474. "\\)"
  475. "[^]]*\\]\\)"
  476. )
  477. (1+ pos-or-point) t)
  478. (c-safe (backward-sexp))
  479. (c-backward-syntactic-ws)
  480. (cond
  481. ((eq (char-before) 93) ;; close sq brace (a previous attribute)
  482. (csharp--at-vsemi-p (point))) ;; recurse
  483. ((or
  484. (eq (char-before) 59) ;; semicolon
  485. (eq (char-before) 123) ;; open curly
  486. (eq (char-before) 125)) ;; close curly
  487. t)
  488. ;; attr is used within a line of code
  489. (t nil)))
  490. (t nil)))
  491. (t nil))
  492. )))
  493. ;; ==================================================================
  494. ;; end of csharp-mode utility and feature defuns
  495. ;; ==================================================================
  496. ;; ==================================================================
  497. ;; c# values for "language constants" defined in cc-langs.el
  498. ;; ==================================================================
  499. (c-lang-defconst c-at-vsemi-p-fn
  500. csharp 'csharp--at-vsemi-p)
  501. ;; This c-opt-after-id-concat-key is a regexp that matches
  502. ;; dot. In other words: "\\(\\.\\)"
  503. ;; Not sure why this needs to be so complicated.
  504. ;; This const is now internal (obsolete); need to move to
  505. ;; c-after-id-concat-ops. I don't yet understand the meaning
  506. ;; of that variable, so for now. . . .
  507. ;; (c-lang-defconst c-opt-after-id-concat-key
  508. ;; csharp (if (c-lang-const c-opt-identifier-concat-key)
  509. ;; (c-lang-const c-symbol-start)))
  510. (c-lang-defconst c-opt-after-id-concat-key
  511. csharp "[[:alpha:]_]" )
  512. ;; The matchers elements can be of many forms. It gets pretty
  513. ;; complicated. Do a describe-variable on font-lock-keywords to get a
  514. ;; description. (Why on font-lock-keywords? I don't know, but that's
  515. ;; where you get the help.)
  516. ;;
  517. ;; Aside from the provided documentation, the other option of course, is
  518. ;; to look in the source code as an example for what to do. The source
  519. ;; in cc-fonts uses a defun c-make-font-lock-search-function to produce
  520. ;; most of the matchers. Called this way:
  521. ;;
  522. ;; (c-make-font-lock-search-function regexp '(A B c))
  523. ;;
  524. ;; The REGEXP is used in re-search-forward, and if there's a match, then
  525. ;; A is called within a save-match-data. If B and C are non-nil, they
  526. ;; are called as pre and post blocks, respecitvely.
  527. ;;
  528. ;; Anyway the c-make-font-lock-search-function works for a single regex,
  529. ;; but more complicated scenarios such as those intended to match and
  530. ;; fontify object initializers, call for a hand-crafted lambda.
  531. ;;
  532. ;; The object initializer is special because matching on it must
  533. ;; allow nesting.
  534. ;;
  535. ;; In c#, the object initializer block is used directly after a
  536. ;; constructor, like this:
  537. ;;
  538. ;; new MyType
  539. ;; {
  540. ;; Prop1 = "foo"
  541. ;; }
  542. ;;
  543. ;; csharp-mode needs to fontify the properties in the
  544. ;; initializer block in font-lock-variable-name-face. The key thing is
  545. ;; to set the text property on the open curly, using type c-type and
  546. ;; value c-decl-id-start. This apparently allows `parse-partial-sexp' to
  547. ;; do the right thing, later.
  548. ;;
  549. ;; This simple case is easy to handle in a regex, using the basic
  550. ;; `c-make-font-lock-search-function' form. But the general syntax for a
  551. ;; constructor + object initializer in C# is more complex:
  552. ;;
  553. ;; new MyType(..arglist..) {
  554. ;; Prop1 = "foo"
  555. ;; }
  556. ;;
  557. ;; A simple regex match won't satisfy here, because the ..arglist.. can
  558. ;; be anything, including calls to other constructors, potentially with
  559. ;; object initializer blocks. This may nest arbitrarily deeply, and the
  560. ;; regex in emacs doesn't support balanced matching. Therefore there's
  561. ;; no way to match on the "outside" pair of parens, to find the relevant
  562. ;; open curly. What's necessary is to do the match on "new MyType" then
  563. ;; skip over the sexp defined by the parens, then set the text property on
  564. ;; the appropriate open-curly.
  565. ;;
  566. ;; To make that happen, it's good to have insight into what the matcher
  567. ;; really does. The output of `c-make-font-lock-search-function' before
  568. ;; byte-compiling, is:
  569. ;;
  570. ;; (lambda (limit)
  571. ;; (let ((parse-sexp-lookup-properties
  572. ;; (cc-eval-when-compile
  573. ;; (boundp 'parse-sexp-lookup-properties))))
  574. ;; (while (re-search-forward REGEX limit t)
  575. ;; (unless
  576. ;; (progn
  577. ;; (goto-char (match-beginning 0))
  578. ;; (c-skip-comments-and-strings limit))
  579. ;; (goto-char (match-end 0))
  580. ;; (progn
  581. ;; B
  582. ;; (save-match-data A)
  583. ;; C ))))
  584. ;; nil)
  585. ;;
  586. ;; csharp-mode uses this hand-crafted form of a matcher to handle the
  587. ;; general case for constructor + object initializer, within
  588. ;; `c-basic-matchers-after' .
  589. ;;
  590. ;; (defun c-make-font-lock-search-function (regexp &rest highlights)
  591. ;; ;; This function makes a byte compiled function that works much like
  592. ;; ;; a matcher element in `font-lock-keywords'. It cuts out a little
  593. ;; ;; bit of the overhead compared to a real matcher. The main reason
  594. ;; ;; is however to pass the real search limit to the anchored
  595. ;; ;; matcher(s), since most (if not all) font-lock implementations
  596. ;; ;; arbitrarily limits anchored matchers to the same line, and also
  597. ;; ;; to insulate against various other irritating differences between
  598. ;; ;; the different (X)Emacs font-lock packages.
  599. ;; ;;
  600. ;; ;; REGEXP is the matcher, which must be a regexp. Only matches
  601. ;; ;; where the beginning is outside any comment or string literal are
  602. ;; ;; significant.
  603. ;; ;;
  604. ;; ;; HIGHLIGHTS is a list of highlight specs, just like in
  605. ;; ;; `font-lock-keywords', with these limitations: The face is always
  606. ;; ;; overridden (no big disadvantage, since hits in comments etc are
  607. ;; ;; filtered anyway), there is no "laxmatch", and an anchored matcher
  608. ;; ;; is always a form which must do all the fontification directly.
  609. ;; ;; `limit' is a variable bound to the real limit in the context of
  610. ;; ;; the anchored matcher forms.
  611. ;; ;;
  612. ;; ;; This function does not do any hidden buffer changes, but the
  613. ;; ;; generated functions will. (They are however used in places
  614. ;; ;; covered by the font-lock context.)
  615. ;;
  616. ;; ;; Note: Replace `byte-compile' with `eval' to debug the generated
  617. ;; ;; lambda easier.
  618. ;; (byte-compile
  619. ;; `(lambda (limit)
  620. ;; (let (;; The font-lock package in Emacs is known to clobber
  621. ;; ;; `parse-sexp-lookup-properties' (when it exists).
  622. ;; (parse-sexp-lookup-properties
  623. ;; (cc-eval-when-compile
  624. ;; (boundp 'parse-sexp-lookup-properties))))
  625. ;; (while (re-search-forward ,regexp limit t)
  626. ;; (unless (progn
  627. ;; (goto-char (match-beginning 0))
  628. ;; (c-skip-comments-and-strings limit))
  629. ;; (goto-char (match-end 0))
  630. ;; ,@(mapcar
  631. ;; (lambda (highlight)
  632. ;; (if (integerp (car highlight))
  633. ;; (progn
  634. ;; (unless (eq (nth 2 highlight) t)
  635. ;; (error
  636. ;; "The override flag must currently be t in %s"
  637. ;; highlight))
  638. ;; (when (nth 3 highlight)
  639. ;; (error
  640. ;; "The laxmatch flag may currently not be set in %s"
  641. ;; highlight))
  642. ;; `(save-match-data
  643. ;; (c-put-font-lock-face
  644. ;; (match-beginning ,(car highlight))
  645. ;; (match-end ,(car highlight))
  646. ;; ,(elt highlight 1))))
  647. ;; (when (nth 3 highlight)
  648. ;; (error "Match highlights currently not supported in %s"
  649. ;; highlight))
  650. ;; `(progn
  651. ;; ,(nth 1 highlight)
  652. ;; (save-match-data ,(car highlight))
  653. ;; ,(nth 2 highlight))))
  654. ;; highlights))))
  655. ;; nil))
  656. ;; )
  657. (c-lang-defconst c-basic-matchers-before
  658. csharp `(
  659. ;;;; Font-lock the attributes by searching for the
  660. ;;;; appropriate regex and marking it as TODO.
  661. ;;,`(,(concat "\\(" csharp-attribute-regex "\\)")
  662. ;; 0 font-lock-function-name-face)
  663. ;; Put a warning face on the opener of unclosed strings that
  664. ;; can't span lines. Later font
  665. ;; lock packages have a `font-lock-syntactic-face-function' for
  666. ;; this, but it doesn't give the control we want since any
  667. ;; fontification done inside the function will be
  668. ;; unconditionally overridden.
  669. ,(c-make-font-lock-search-function
  670. ;; Match a char before the string starter to make
  671. ;; `c-skip-comments-and-strings' work correctly.
  672. (concat ".\\(" c-string-limit-regexp "\\)")
  673. '((if (fboundp 'c-font-lock-invalid-string)
  674. (c-font-lock-invalid-string)
  675. (csharp-mode-font-lock-invalid-string))))
  676. ;; Fontify keyword constants.
  677. ,@(when (c-lang-const c-constant-kwds)
  678. (let ((re (c-make-keywords-re nil
  679. (c-lang-const c-constant-kwds))))
  680. `((eval . (list ,(concat "\\<\\(" re "\\)\\>")
  681. 1 c-constant-face-name)))))
  682. ;; Fontify the namespaces that follow using statements.
  683. ;; This regex handles the optional alias, as well.
  684. ,`(,(concat
  685. "\\<\\(using\\)[ \t\n\f\v\r]+"
  686. "\\(?:"
  687. "\\([A-Za-z0-9_]+\\)"
  688. "[ \t\n\f\v\r]*="
  689. "[ \t\n\f\v\r]*"
  690. "\\)?"
  691. "\\(\\(?:[A-Za-z0-9_]+\\.\\)*[A-Za-z0-9_]+\\)"
  692. "[ \t\n\f\v\r]*;")
  693. (2 font-lock-constant-face t t)
  694. (3 font-lock-constant-face))
  695. ;; Fontify all keywords except the primitive types.
  696. ,`(,(concat "\\<" (c-lang-const c-regular-keywords-regexp))
  697. 1 font-lock-keyword-face)
  698. ))
  699. (c-lang-defconst c-basic-matchers-after
  700. csharp `(
  701. ;; option 1:
  702. ;; ,@(when condition
  703. ;; `((,(byte-compile
  704. ;; `(lambda (limit) ...
  705. ;;
  706. ;; option 2:
  707. ;; ,`((lambda (limit) ...
  708. ;;
  709. ;; I don't know how to avoid the (when condition ...) in the
  710. ;; byte-compiled version.
  711. ;;
  712. ;; X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+
  713. ;; Case 1: invocation of constructor + maybe an object
  714. ;; initializer. Some possible examples that satisfy:
  715. ;;
  716. ;; new Foo ();
  717. ;;
  718. ;; new Foo () { };
  719. ;;
  720. ;; new Foo { };
  721. ;;
  722. ;; new Foo { Prop1= 7 };
  723. ;;
  724. ;; new Foo {
  725. ;; Prop1= 7
  726. ;; };
  727. ;;
  728. ;; new Foo {
  729. ;; Prop1= 7,
  730. ;; Prop2= "Fred"
  731. ;; };
  732. ;;
  733. ;; new Foo {
  734. ;; Prop1= new Bar()
  735. ;; };
  736. ;;
  737. ;; new Foo {
  738. ;; Prop1= new Bar { PropA = 5.6F }
  739. ;; };
  740. ;;
  741. ,@(when t
  742. `((,(byte-compile
  743. `(lambda (limit)
  744. (let ((parse-sexp-lookup-properties
  745. (cc-eval-when-compile
  746. (boundp 'parse-sexp-lookup-properties))))
  747. (while (re-search-forward
  748. ,(concat "\\<new"
  749. "[ \t\n\r\f\v]+"
  750. "\\(\\(?:"
  751. (c-lang-const c-symbol-key)
  752. "\\.\\)*"
  753. (c-lang-const c-symbol-key)
  754. "\\)"
  755. )
  756. limit t)
  757. (unless
  758. (progn
  759. (goto-char (match-beginning 0))
  760. (c-skip-comments-and-strings limit))
  761. (csharp-log 3 "ctor invoke? at %d" (match-beginning 1))
  762. (save-match-data
  763. ;; next thing could be: [] () <> or {} or nothing (semicolon, comma).
  764. ;; fontify the typename
  765. (c-put-font-lock-face (match-beginning 1)
  766. (match-end 1)
  767. 'font-lock-type-face)
  768. (goto-char (match-end 0))
  769. (c-forward-syntactic-ws limit)
  770. (if (eq (char-after) ?<) ;; ctor for generic type
  771. (progn
  772. (csharp-log 3 " - this is a generic type")
  773. ;; skip over <> safely
  774. (c-safe (c-forward-sexp 1) t)
  775. (c-forward-syntactic-ws)))
  776. ;; now, could be [] or (..) or {..} or semicolon.
  777. (csharp-log 3 " - looking for sexp")
  778. (if (or
  779. (eq (char-after) ?{) ;; open curly
  780. ;; is square parenthesis block? - start
  781. (let* ((start (point)) ;; used to hold our position, so that we know that
  782. (end)) ;; our code isn't stuck trying to look for a non-existant sexp.
  783. (and (eq (char-after) 91) ;; open square
  784. (while (and (eq (char-after) 91)
  785. (not (eq start end)))
  786. (c-safe (c-forward-sexp 1))
  787. (setq end (point)))
  788. (eq (char-before) 93)))
  789. ;; is square parenthesis block? - end
  790. (and (eq (char-after) 40) ;; open paren
  791. (c-safe (c-forward-sexp 1) t)))
  792. (progn
  793. ;; at this point we've jumped over any intervening s-exp,
  794. ;; like sq brackets or parens.
  795. (c-forward-syntactic-ws)
  796. (csharp-log 3 " - after fwd-syn-ws point(%d)" (point))
  797. (csharp-log 3 " - next char: %c" (char-after))
  798. (if (eq (char-after) ?{)
  799. (let ((start (point))
  800. (end (if (c-safe (c-forward-sexp 1) t)
  801. (point) 0)))
  802. (csharp-log 3 " - open curly gets c-decl-id-start %d" start)
  803. (c-put-char-property start
  804. 'c-type
  805. 'c-decl-id-start)
  806. (goto-char start)
  807. (if (> end start)
  808. (progn
  809. (forward-char 1) ;; step over open curly
  810. (c-forward-syntactic-ws)
  811. (while (> end (point))
  812. ;; now, try to fontify/assign variables to any properties inside the curlies
  813. (csharp-log 3 " - inside open curly point(%d)" (point))
  814. (csharp-log 3 " - next char: %c" (char-after))
  815. ;; fontify each property assignment
  816. (if (re-search-forward
  817. (concat "\\(" (c-lang-const c-symbol-key) "\\)\\s*=")
  818. end t)
  819. (progn
  820. (csharp-log 3 " - found variable %d-%d"
  821. (match-beginning 1)
  822. (match-end 1))
  823. (c-put-font-lock-face (match-beginning 1)
  824. (match-end 1)
  825. 'font-lock-variable-name-face)
  826. (goto-char (match-end 0))
  827. (c-forward-syntactic-ws)
  828. ;; advance to the next assignment, if possible
  829. (if (eq (char-after) ?@)
  830. (forward-char 1))
  831. (if (c-safe (c-forward-sexp 1) t)
  832. (progn
  833. (forward-char 1)
  834. (c-forward-syntactic-ws))))
  835. ;; else
  836. (csharp-log 3 " - no more assgnmts found")
  837. (goto-char end)))))
  838. )))))
  839. (goto-char (match-end 0))
  840. )))
  841. nil))
  842. )))
  843. ;; Case 2: declaration of enum with or without an explicit
  844. ;; base type.
  845. ;;
  846. ;; Examples:
  847. ;;
  848. ;; public enum Foo { ... }
  849. ;;
  850. ;; public enum Foo : uint { ... }
  851. ;;
  852. ,@(when t
  853. `((,(byte-compile
  854. `(lambda (limit)
  855. (let ((parse-sexp-lookup-properties
  856. (cc-eval-when-compile
  857. (boundp 'parse-sexp-lookup-properties))))
  858. (while (re-search-forward
  859. ,(concat csharp-enum-decl-re
  860. "[ \t\n\r\f\v]*"
  861. "{")
  862. limit t)
  863. (csharp-log 3 "enum? at %d" (match-beginning 0))
  864. (unless
  865. (progn
  866. (goto-char (match-beginning 0))
  867. (c-skip-comments-and-strings limit))
  868. (progn
  869. (save-match-data
  870. (goto-char (match-end 0))
  871. (c-put-char-property (1- (point))
  872. 'c-type
  873. 'c-decl-id-start)
  874. (c-forward-syntactic-ws))
  875. (save-match-data
  876. (with-no-warnings
  877. (condition-case nil
  878. (c-font-lock-declarators limit t nil)
  879. (wrong-number-of-arguments
  880. (c-font-lock-declarators limit t nil nil)))))
  881. (goto-char (match-end 0))
  882. )
  883. )))
  884. nil))
  885. )))
  886. ;; Case 4: using clause. Without this, using (..) gets fontified as a fn.
  887. ,@(when t
  888. `((,(byte-compile
  889. `(lambda (limit)
  890. (let ((parse-sexp-lookup-properties
  891. (cc-eval-when-compile
  892. (boundp 'parse-sexp-lookup-properties))))
  893. (while (re-search-forward
  894. ,(concat "\\<\\(using\\)"
  895. "[ \t\n\r\f\v]*"
  896. "(")
  897. limit t)
  898. (csharp-log 3 "using clause p(%d)" (match-beginning 0))
  899. (unless
  900. (progn
  901. (goto-char (match-beginning 0))
  902. (c-skip-comments-and-strings limit))
  903. (save-match-data
  904. (c-put-font-lock-face (match-beginning 1)
  905. (match-end 1)
  906. 'font-lock-keyword-face)
  907. (goto-char (match-end 0))))))
  908. nil))
  909. )))
  910. ;; Case 5: attributes
  911. ,`((lambda (limit)
  912. (let ((parse-sexp-lookup-properties
  913. (cc-eval-when-compile
  914. (boundp 'parse-sexp-lookup-properties))))
  915. (while (re-search-forward
  916. ,(concat "[ \t\n\r\f\v]+"
  917. "\\(\\["
  918. "[ \t\n\r\f\v]*"
  919. "\\(?:\\(?:return\\|assembly\\)[ \t]*:[ \t]*\\)?"
  920. "\\("
  921. "\\(?:[A-Za-z_][[:alnum:]]*\\.\\)*"
  922. "[A-Za-z_][[:alnum:]]*"
  923. "\\)"
  924. "[^]]*\\]\\)"
  925. )
  926. limit t)
  927. (csharp-log 3 "attribute? - %d limit(%d)" (match-beginning 1)
  928. limit)
  929. (unless
  930. (progn
  931. (goto-char (match-beginning 1))
  932. (c-skip-comments-and-strings limit))
  933. (let ((b2 (match-beginning 2))
  934. (e2 (match-end 2))
  935. (is-attr nil))
  936. (csharp-log 3 " - type match: %d - %d"
  937. b2 e2)
  938. (save-match-data
  939. (c-backward-syntactic-ws)
  940. (setq is-attr (or
  941. (eq (char-before) 59) ;; semicolon
  942. (eq (char-before) 93) ;; close square brace
  943. (eq (char-before) 123) ;; open curly
  944. (eq (char-before) 125) ;; close curly
  945. (save-excursion
  946. (c-beginning-of-statement-1)
  947. (looking-at
  948. "#\\s *\\(pragma\\|endregion\\|region\\|if\\|else\\|endif\\)"))
  949. )))
  950. (if is-attr
  951. (progn
  952. (if (<= 3 csharp-log-level)
  953. (csharp-log 3 " - attribute: '%s'"
  954. (buffer-substring-no-properties b2 e2)))
  955. (c-put-font-lock-face b2 e2 'font-lock-type-face)))))
  956. (goto-char (match-end 0))
  957. ))
  958. nil))
  959. ;; Fontify labels after goto etc.
  960. ,@(when (c-lang-const c-before-label-kwds)
  961. `( ;; (Got three different interpretation levels here,
  962. ;; which makes it a bit complicated: 1) The backquote
  963. ;; stuff is expanded when compiled or loaded, 2) the
  964. ;; eval form is evaluated at font-lock setup (to
  965. ;; substitute c-label-face-name correctly), and 3) the
  966. ;; resulting structure is interpreted during
  967. ;; fontification.)
  968. (eval
  969. . ,(let* ((c-before-label-re
  970. (c-make-keywords-re nil
  971. (c-lang-const c-before-label-kwds))))
  972. `(list
  973. ,(concat "\\<\\(" c-before-label-re "\\)\\>"
  974. "\\s *"
  975. "\\(" ; identifier-offset
  976. (c-lang-const c-symbol-key)
  977. "\\)")
  978. (list ,(+ (regexp-opt-depth c-before-label-re) 2)
  979. c-label-face-name nil t))))))
  980. ;; Fontify the clauses after various keywords.
  981. ,@(when (or (c-lang-const c-type-list-kwds)
  982. (c-lang-const c-ref-list-kwds)
  983. (c-lang-const c-colon-type-list-kwds)
  984. (c-lang-const c-paren-type-kwds))
  985. `((,(c-make-font-lock-search-function
  986. (concat "\\<\\("
  987. (c-make-keywords-re nil
  988. (append (c-lang-const c-type-list-kwds)
  989. (c-lang-const c-ref-list-kwds)
  990. (c-lang-const c-colon-type-list-kwds)
  991. (c-lang-const c-paren-type-kwds)))
  992. "\\)\\>")
  993. '((c-fontify-types-and-refs ((c-promote-possible-types t))
  994. (c-forward-keyword-clause 1)
  995. (if (> (point) limit) (goto-char limit))))))))
  996. ;; Fontify the name that follows each namespace declaration
  997. ;; this needs to be done in the matchers-after because
  998. ;; otherwise the namespace names get the font-lock-type-face,
  999. ;; due to the energetic efforts of c-forward-type.
  1000. ,`("\\<\\(namespace\\)[ \t\n\r\f\v]+\\(\\(?:[A-Za-z0-9_]+\\.\\)*[A-Za-z0-9_]+\\)"
  1001. 2 font-lock-constant-face t)
  1002. ;; Highlight function-invocation.
  1003. ;; (this may in the future use font-lock-function-call-face, if standardized)
  1004. ,`(,"\\.\\([A-Za-z0-9_]+\\)("
  1005. 1 font-lock-function-name-face t)
  1006. ))
  1007. ;; verbatim string literals can be multiline
  1008. (c-lang-defconst c-multiline-string-start-char
  1009. csharp ?@)
  1010. (defun csharp-mode-syntax-propertize-function (beg end)
  1011. "Apply syntax table properties to special constructs in region BEG to END.
  1012. Currently handled:
  1013. - Fontify verbatim literal strings correctly
  1014. - Highlight text after #region or #pragma as comment"
  1015. (save-excursion
  1016. (goto-char beg)
  1017. (while (search-forward "@\"" end t)
  1018. (let ((in-comment-or-string-p (save-excursion
  1019. (goto-char (match-beginning 0))
  1020. (or (nth 3 (syntax-ppss))
  1021. (nth 4 (syntax-ppss))))))
  1022. (when (not in-comment-or-string-p)
  1023. (let (done)
  1024. (while (and (not done) (< (point) end))
  1025. (skip-chars-forward "^\"\\\\" end)
  1026. (cond
  1027. ((= (following-char) ?\\)
  1028. (put-text-property (point) (1+ (point))
  1029. 'syntax-table (string-to-syntax "."))
  1030. (forward-char 1))
  1031. ((= (following-char) ?\")
  1032. (forward-char 1)
  1033. (if (= (following-char) ?\")
  1034. (progn
  1035. (put-text-property (1- (point)) (1+ (point))
  1036. 'syntax-table (string-to-syntax "/"))
  1037. (forward-char 1))
  1038. (setq done t)))))))))
  1039. (goto-char beg)
  1040. (while (re-search-forward "^\\s *#\\s *\\(region\\|pragma\\)\\s " end t)
  1041. (when (looking-at "\\s *\\S ")
  1042. ;; mark the whitespace separating the directive from the comment
  1043. ;; text as comment starter to allow correct word movement
  1044. (put-text-property (1- (point)) (point)
  1045. 'syntax-table (string-to-syntax "< b"))))))
  1046. ;; C# does generics. Setting this to t tells the parser to put
  1047. ;; parenthesis syntax on angle braces that surround a comma-separated
  1048. ;; list.
  1049. (c-lang-defconst c-recognize-<>-arglists
  1050. csharp t)
  1051. (c-lang-defconst c-identifier-key
  1052. csharp (concat "\\([[:alpha:]_][[:alnum:]_]*\\)" ; 1
  1053. "\\("
  1054. "[ \t\n\r\f\v]*"
  1055. "\\(\\.\\)" ;;(c-lang-const c-opt-identifier-concat-key)
  1056. "[ \t\n\r\f\v]*"
  1057. "\\(\\([[:alpha:]_][[:alnum:]_]*\\)\\)"
  1058. "\\)*"))
  1059. ;; C# has a few rules that are slightly different than Java for
  1060. ;; operators. This also removed the Java's "super" and replaces it
  1061. ;; with the C#'s "base".
  1062. (c-lang-defconst c-operators
  1063. csharp `((prefix "base")))
  1064. ;; C# uses CPP-like prefixes to mark #define, #region/endregion,
  1065. ;; #if/else/endif, and #pragma. This regexp matches the prefix, not
  1066. ;; including the beginning-of-line (BOL), and not including the term
  1067. ;; after the prefix (define, pragma, region, etc). This regexp says
  1068. ;; whitespace, followed by the prefix, followed by maybe more
  1069. ;; whitespace.
  1070. (c-lang-defconst c-opt-cpp-prefix
  1071. csharp "\\s *#\\s *")
  1072. ;; there are no message directives in C#
  1073. (c-lang-defconst c-cpp-message-directives
  1074. csharp nil)
  1075. (c-lang-defconst c-cpp-expr-directives
  1076. csharp '("if"))
  1077. (c-lang-defconst c-opt-cpp-macro-define
  1078. csharp "define")
  1079. ;; $ is not a legal char in an identifier in C#. So we need to
  1080. ;; create a csharp-specific definition of this constant.
  1081. (c-lang-defconst c-symbol-chars
  1082. csharp (concat c-alnum "_"))
  1083. ;; c-identifier-syntax-modifications by default defines $ as a word
  1084. ;; syntax, which is not legal in C#. So, define our own lang-specific
  1085. ;; value.
  1086. (c-lang-defconst c-identifier-syntax-modifications
  1087. csharp '((?_ . "w")))
  1088. (c-lang-defconst c-colon-type-list-kwds
  1089. csharp '("class" "struct" "interface"))
  1090. (c-lang-defconst c-block-prefix-disallowed-chars
  1091. ;; Allow ':' for inherit list starters.
  1092. csharp (cl-set-difference (c-lang-const c-block-prefix-disallowed-chars)
  1093. '(?: ?,)))
  1094. (c-lang-defconst c-assignment-operators
  1095. csharp '("=" "*=" "/=" "%=" "+=" "-=" ">>=" "<<=" "&=" "^=" "|="))
  1096. (c-lang-defconst c-primitive-type-kwds
  1097. ;; ECMA-344, S8
  1098. csharp '("object" "string" "sbyte" "short" "int" "long" "byte"
  1099. "ushort" "uint" "ulong" "float" "double" "bool" "char"
  1100. "decimal" "void"))
  1101. ;; The keywords that define that the following is a type, such as a
  1102. ;; class definition.
  1103. (c-lang-defconst c-type-prefix-kwds
  1104. ;; ECMA-344, S?
  1105. csharp '("class" "interface" "struct")) ;; no enum here.
  1106. ;; we want enum to be a brace list.
  1107. ;; Type modifier keywords. They appear anywhere in types, but modify
  1108. ;; instead of create one.
  1109. (c-lang-defconst c-type-modifier-kwds
  1110. ;; EMCA-344, S?
  1111. csharp '("readonly" "const" "volatile" "new"))
  1112. ;; Tue, 20 Apr 2010 16:02
  1113. ;; need to verify that this works for lambdas...
  1114. (c-lang-defconst c-special-brace-lists
  1115. csharp '((?{ . ?}) ))
  1116. ;; dinoch
  1117. ;; Thu, 22 Apr 2010 18:54
  1118. ;;
  1119. ;; No idea why this isn't getting set properly in the first place.
  1120. ;; In cc-langs.el, it is set to the union of a bunch of things, none
  1121. ;; of which include "new", or "enum".
  1122. ;;
  1123. ;; But somehow both of those show up in the resulting derived regexp.
  1124. ;; This breaks indentation of instance initializers, such as
  1125. ;;
  1126. ;; var x = new Foo { ... };
  1127. ;;
  1128. ;; Based on my inspection, the existing c-lang-defconst should work!
  1129. ;; I don't know how to fix this c-lang-defconst, so I am re-setting this
  1130. ;; variable here, to provide the regex explicitly.
  1131. ;;
  1132. (c-lang-defconst c-decl-block-key
  1133. csharp '"\\(namespace\\)\\([^[:alnum:]_]\\|$\\)\\|\\(class\\|interface\\|struct\\)\\([^[:alnum:]_]\\|$\\)" )
  1134. ;; Thu, 22 Apr 2010 14:29
  1135. ;; I want this to handle var x = new Foo[] { ... };
  1136. ;; not sure if necessary.
  1137. (c-lang-defconst c-inexpr-brace-list-kwds
  1138. csharp '("new"))
  1139. ;; ;;(c-lang-defconst c-inexpr-class-kwds
  1140. ;; ;; csharp '("new"))
  1141. (c-lang-defconst c-class-decl-kwds
  1142. ;; EMCA-344, S?
  1143. ;; don't include enum here, because we want it to be fontified as a brace
  1144. ;; list, with commas delimiting the values. see c-brace-list-decl-kwds
  1145. ;; below.
  1146. csharp '("class" "interface" "struct" )) ;; no "enum"!!
  1147. ;; The various modifiers used for class and method descriptions.
  1148. (c-lang-defconst c-modifier-kwds
  1149. csharp '("public" "partial" "private" "const" "abstract" "sealed"
  1150. "protected" "ref" "out" "static" "virtual"
  1151. "implicit" "explicit" "fixed"
  1152. "override" "params" "internal" "async" "extern" "unsafe"))
  1153. ;; Thu, 22 Apr 2010 23:02
  1154. ;; Based on inspection of the cc-mode code, the c-protection-kwds
  1155. ;; c-lang-const is used only for objective-c. So the value is
  1156. ;; irrelevant for csharp.
  1157. (c-lang-defconst c-protection-kwds
  1158. csharp nil
  1159. ;; csharp '("private" "protected" "public" "internal")
  1160. )
  1161. (c-lang-defconst c-opt-op-identifier-prefix
  1162. "Regexp matching the token before the ones in
  1163. `c-overloadable-operators' when operators are specified in their \"identifier form\".
  1164. This regexp is assumed to not match any non-operator identifier."
  1165. csharp (c-make-keywords-re t '("operator")))
  1166. ;; Define the keywords that can have something following after them.
  1167. (c-lang-defconst c-type-list-kwds
  1168. csharp '("struct" "class" "interface" "is" "as" "operator"
  1169. "delegate" "event" "set" "get" "add" "remove"))
  1170. ;; Handle typeless variable declaration
  1171. (c-lang-defconst c-typeless-decl-kwds
  1172. csharp '("var"))
  1173. ;; Sets up the enum to handle the list properly, and also the new
  1174. ;; keyword to handle object initializers. This requires a modified
  1175. ;; c-basic-matchers-after (see above) in order to correctly fontify C#
  1176. ;; 3.0 object initializers.
  1177. (c-lang-defconst c-brace-list-decl-kwds
  1178. csharp '("enum" "new"))
  1179. ;; Statement keywords followed directly by a substatement.
  1180. ;; catch is not one of them, because catch has a paren (typically).
  1181. (c-lang-defconst c-block-stmt-1-kwds
  1182. csharp '("do" "else" "try" "finally"))
  1183. ;; Statement keywords followed by a paren sexp and then by a substatement.
  1184. (c-lang-defconst c-block-stmt-2-kwds
  1185. csharp '("for" "if" "switch" "while" "catch" "foreach" "using"
  1186. "fixed"
  1187. "checked" "unchecked" "lock"))
  1188. ;; Statements that break out of braces
  1189. (c-lang-defconst c-simple-stmt-kwds
  1190. csharp '("return" "continue" "break" "throw" "goto" ))
  1191. ;; Statements that allow a label
  1192. ;; TODO?
  1193. (c-lang-defconst c-before-label-kwds
  1194. csharp nil)
  1195. ;; Constant keywords
  1196. (c-lang-defconst c-constant-kwds
  1197. csharp '("true" "false" "null" "value"))
  1198. ;; Keywords that start "primary expressions."
  1199. (c-lang-defconst c-primary-expr-kwds
  1200. csharp '("this" "base" "operator"))
  1201. ;; Treat namespace as an outer block so class indenting
  1202. ;; works properly.
  1203. (c-lang-defconst c-other-block-decl-kwds
  1204. csharp '("namespace"))
  1205. (c-lang-defconst c-other-kwds
  1206. csharp '("sizeof" "typeof" "is" "as" "yield"
  1207. "where" "select" "in" "from" "let" "orderby" "ascending" "descending"
  1208. "await" "async"))
  1209. (c-lang-defconst c-overloadable-operators
  1210. ;; EMCA-344, S14.2.1
  1211. csharp '("+" "-" "*" "/" "%" "&" "|" "^"
  1212. "<<" ">>" "==" "!=" ">" "<" ">=" "<="))
  1213. ;; This c-cpp-matchers stuff is used for fontification.
  1214. ;; see cc-font.el
  1215. ;;
  1216. ;; There's no preprocessor in C#, but there are still compiler
  1217. ;; directives to fontify: "#pragma", #region/endregion, #define, #undef,
  1218. ;; #if/else/endif. (The definitions for the extra keywords above are
  1219. ;; enough to incorporate them into the fontification regexps for types
  1220. ;; and keywords, so no additional font-lock patterns are required for
  1221. ;; keywords.)
  1222. (c-lang-defconst c-cpp-matchers
  1223. csharp (cons
  1224. ;; Use the eval form for `font-lock-keywords' to be able to use
  1225. ;; the `c-preprocessor-face-name' variable that maps to a
  1226. ;; suitable face depending on the (X)Emacs version.
  1227. '(eval . (list "^\\s *#\\s *\\(pragma\\|undef\\|define\\)\\>\\(.*\\)"
  1228. (list 1 c-preprocessor-face-name)
  1229. '(2 font-lock-string-face)))
  1230. ;; There are some other things in `c-cpp-matchers' besides the
  1231. ;; preprocessor support, so include it.
  1232. (c-lang-const c-cpp-matchers)))
  1233. ;; allow strings as switch-case values by leaving out string
  1234. ;; delimiters in this definition
  1235. (c-lang-defconst c-nonlabel-token-key
  1236. csharp (c-make-keywords-re t
  1237. (cl-set-difference (c-lang-const c-keywords)
  1238. (append (c-lang-const c-label-kwds)
  1239. (c-lang-const c-protection-kwds))
  1240. :test 'string-equal)))
  1241. (defconst csharp-font-lock-keywords-1 (c-lang-const c-matchers-1 csharp)
  1242. "Minimal highlighting for C# mode.")
  1243. (defconst csharp-font-lock-keywords-2 (c-lang-const c-matchers-2 csharp)
  1244. "Fast normal highlighting for C# mode.")
  1245. (defconst csharp-font-lock-keywords-3 (c-lang-const c-matchers-3 csharp)
  1246. "Accurate normal highlighting for C# mode.")
  1247. (defvar csharp-font-lock-keywords csharp-font-lock-keywords-3
  1248. "Default expressions to highlight in C# mode.")
  1249. (defvar csharp-mode-syntax-table nil
  1250. "Syntax table used in ‘csharp-mode’ buffers.")
  1251. (or csharp-mode-syntax-table
  1252. (setq csharp-mode-syntax-table
  1253. (funcall (c-lang-const c-make-mode-syntax-table csharp))))
  1254. (defvar csharp-mode-abbrev-table nil
  1255. "Abbreviation table used in ‘csharp-mode’ buffers.")
  1256. (c-define-abbrev-table 'csharp-mode-abbrev-table
  1257. ;; Keywords that if they occur first on a line might alter the
  1258. ;; syntactic context, and which therefore should trig reindentation
  1259. ;; when they are completed.
  1260. '(("else" "else" c-electric-continued-statement 0)
  1261. ("while" "while" c-electric-continued-statement 0)
  1262. ("catch" "catch" c-electric-continued-statement 0)
  1263. ("finally" "finally" c-electric-continued-statement 0)))
  1264. (defvar csharp-mode-map (let ((map (c-make-inherited-keymap)))
  1265. ;; Add bindings which are only useful for C#
  1266. map)
  1267. "Keymap used in ‘csharp-mode’ buffers.")
  1268. ;; TODO
  1269. ;; Defines our constant for finding attributes.
  1270. ;;(defconst csharp-attribute-regex "\\[\\([XmlType]+\\)(")
  1271. ;;(defconst csharp-attribute-regex "\\[\\(.\\)")
  1272. ;; This doesn't work because the string regex happens before this point
  1273. ;; and getting the font-locking to work before and after is fairly difficult
  1274. ;;(defconst csharp-attribute-regex
  1275. ;; (concat
  1276. ;; "\\[[a-zA-Z][ \ta-zA-Z0-9.]+"
  1277. ;; "\\((.*\\)?"
  1278. ;;))
  1279. ;; ==================================================================
  1280. ;; end of c# values for "language constants" defined in cc-langs.el
  1281. ;; ==================================================================
  1282. ;; ========================================================================
  1283. ;; moving
  1284. ;; alist of regexps for various structures in a csharp source file.
  1285. (defconst csharp--regexp-alist
  1286. (list
  1287. `(func-start
  1288. ,(concat
  1289. "^[ \t\n\r\f\v]*" ;; leading whitespace
  1290. "\\("
  1291. "public\\(?: static\\)?\\|" ;; 1. access modifier
  1292. "private\\(?: static\\)?\\|"
  1293. "protected\\(?: internal\\)?\\(?: static\\)?\\|"
  1294. "static\\|"
  1295. "\\)"
  1296. "[ \t\n\r\f\v]+"
  1297. "\\(?:override[ \t\n\r\f\v]+\\)?" ;; optional
  1298. "\\([[:alpha:]_][^\t\(\n]+\\)" ;; 2. return type - possibly generic
  1299. "[ \t\n\r\f\v]+"
  1300. "\\(" ;; 3. begin name of func
  1301. "\\(?:[A-Za-z_][[:alnum:]_]*\\.\\)*" ;; possible prefix interface
  1302. "[[:alpha:]_][[:alnum:]_]*" ;; actual func name
  1303. "\\(?:<\\(?:[[:alpha:]][[:alnum:]]*\\)\\(?:[, ]+[[:alpha:]][[:alnum:]]*\\)*>\\)?" ;; (with optional generic type parameter(s)
  1304. "\\)" ;; 3. end of name of func
  1305. "[ \t\n\r\f\v]*"
  1306. "\\(\([^\)]*\)\\)" ;; 4. params w/parens
  1307. "\\(?:[ \t]*/[/*].*\\)?" ;; optional comment at end of line
  1308. "[ \t\n\r\f\v]*"
  1309. ))
  1310. `(class-start
  1311. ,(concat
  1312. "^[ \t]*" ;; leading whitespace
  1313. "\\("
  1314. "public\\(?: \\(?:static\\|sealed\\)\\)?[ \t]+\\|" ;; access modifiers
  1315. "internal\\(?: \\(?:static\\|sealed\\)\\)?[ \t]+\\|"
  1316. "static\\(?: internal\\)?[ \t]+\\|"
  1317. "sealed\\(?: internal\\)?[ \t]+\\|"
  1318. "static[ \t]+\\|"
  1319. "sealed[ \t]+\\|"
  1320. "\\)"
  1321. "\\(\\(?:partial[ \t]+\\)?class\\|struct\\)" ;; class/struct keyword
  1322. "[ \t]+"
  1323. "\\([[:alpha:]_][[:alnum:]]*\\)" ;; type name
  1324. "\\("
  1325. "[ \t\n]*:[ \t\n]*" ;; colon
  1326. "\\([[:alpha:]_][^\t\(\n]+\\)" ;; base / intf - poss generic
  1327. "\\("
  1328. "[ \t\n]*,[ \t\n]*"
  1329. "\\([[:alpha:]_][^\t\(\n]+\\)" ;; addl interface - poss generic
  1330. "\\)*"
  1331. "\\)?" ;; possibly
  1332. "[ \t\n\r\f\v]*"
  1333. ))
  1334. `(namespace-start
  1335. ,(concat
  1336. "^[ \t\f\v]*" ;; leading whitespace
  1337. "\\(namespace\\)"
  1338. "[ \t\n\r\f\v]+"
  1339. "\\("
  1340. "\\(?:[A-Za-z_][[:alnum:]_]*\\.\\)*" ;; name of namespace
  1341. "[A-Za-z_][[:alnum:]]*"
  1342. "\\)"
  1343. "[ \t\n\r\f\v]*"
  1344. ))
  1345. ))
  1346. (defun csharp--regexp (symbol)
  1347. "Retrieve a regexp from `csharp--regexp-alist' corresponding to SYMBOL."
  1348. (let ((elt (assoc symbol csharp--regexp-alist)))
  1349. (if elt (cadr elt) nil)))
  1350. (defun csharp-move-back-to-beginning-of-block ()
  1351. "Move to the previous open curly."
  1352. (interactive)
  1353. (re-search-backward "{" (point-min) t))
  1354. (defun csharp--move-back-to-beginning-of-something (must-match &optional must-not-match)
  1355. "Move back to the open-curly that begin *something*.
  1356. *something* is defined by MUST-MATCH, a regexp which must match
  1357. immediately preceding the curly. If MUST-NOT-MATCH is non-nil,
  1358. it is treated as a regexp that must not match immediately
  1359. preceding the curly.
  1360. This is a helper fn for `csharp-move-back-to-beginning-of-defun' and
  1361. `csharp-move-back-to-beginning-of-class'"
  1362. (interactive)
  1363. (let (done
  1364. (found (point))
  1365. (need-to-backup (not (looking-at "{"))))
  1366. (while (not done)
  1367. (if need-to-backup
  1368. (setq found (csharp-move-back-to-beginning-of-block)))
  1369. (if found
  1370. (setq done (and (looking-back must-match nil)
  1371. (or (not must-not-match)
  1372. (not (looking-back must-not-match nil))))
  1373. need-to-backup t)
  1374. (setq done t)))
  1375. found))
  1376. (defun csharp-move-back-to-beginning-of-defun ()
  1377. "Move back to the open-curly that start the enclosing method.
  1378. If point is outside a method, then move back to the
  1379. beginning of the prior method.
  1380. See also, `csharp-move-fwd-to-end-of-defun'."
  1381. (interactive)
  1382. (cond
  1383. ((bobp) nil)
  1384. (t
  1385. (let (found)
  1386. (save-excursion
  1387. ;; handle the case where we're at the top of a fn now.
  1388. ;; if the user is asking to move back, then obviously
  1389. ;; he wants to move back to a *prior* defun.
  1390. (if (and (looking-at "{")
  1391. (looking-back (csharp--regexp 'func-start) nil)
  1392. (not (looking-back (csharp--regexp 'namespace-start) nil)))
  1393. (forward-char -1))
  1394. ;; now do the real work
  1395. (setq found (csharp--move-back-to-beginning-of-something
  1396. (csharp--regexp 'func-start)
  1397. (csharp--regexp 'namespace-start))))
  1398. (if found
  1399. (goto-char found))))))
  1400. (defun csharp--on-defun-open-curly-p ()
  1401. "Return t when point is on the open-curly of a method."
  1402. (and (looking-at "{")
  1403. (not (looking-back (csharp--regexp 'class-start) nil))
  1404. (not (looking-back (csharp--regexp 'namespace-start) nil))
  1405. (looking-back (csharp--regexp 'func-start) nil)))
  1406. (defun csharp--on-class-open-curly-p ()
  1407. "Return t when point is on the open-curly of a class."
  1408. (and (looking-at "{")
  1409. (not (looking-back (csharp--regexp 'namespace-start) nil))
  1410. (looking-back (csharp--regexp 'class-start) nil)))
  1411. (defun csharp-move-fwd-to-end-of-defun ()
  1412. "Move forward to the close-curly that ends the enclosing method.
  1413. If point is outside a method, moves forward to the close-curly that
  1414. defines the end of the next method.
  1415. See also, `csharp-move-back-to-beginning-of-defun'."
  1416. (interactive)
  1417. (let ((really-move
  1418. (lambda ()
  1419. (let ((start (point))
  1420. dest-char)
  1421. (save-excursion
  1422. (csharp-move-back-to-beginning-of-defun)
  1423. (forward-sexp)
  1424. (if (>= (point) start)
  1425. (setq dest-char (point))))
  1426. (if dest-char
  1427. (goto-char dest-char))))))
  1428. (cond
  1429. ;; case 1: end of buffer. do nothing.
  1430. ((eobp) nil)
  1431. ;; case 2: we're at the top of a class
  1432. ((csharp--on-class-open-curly-p)
  1433. (let (found-it)
  1434. (save-excursion
  1435. (forward-char 1) ;; get off the curly
  1436. (setq found-it
  1437. (and ;; look for next open curly
  1438. (re-search-forward "{" (point-max) t)
  1439. (funcall really-move))))
  1440. (if found-it
  1441. (goto-char found-it))))
  1442. ;; case 3: we're at the top of a fn now.
  1443. ((csharp--on-defun-open-curly-p)
  1444. (forward-sexp))
  1445. ;; case 4: we're at the bottom of a fn now (possibly
  1446. ;; after just calling csharp-move-fwd-to-end-of-defun.
  1447. ((and (looking-back "}" nil)
  1448. (save-excursion
  1449. (forward-sexp -1)
  1450. (csharp--on-defun-open-curly-p)))
  1451. (let (found-it)
  1452. (save-excursion
  1453. (setq found-it
  1454. (and (re-search-forward "{" (point-max) t)
  1455. (funcall really-move))))
  1456. (if found-it
  1457. (goto-char found-it))))
  1458. ;; case 5: we're at none of those places.
  1459. (t
  1460. (funcall really-move)))))
  1461. (defun csharp-move-back-to-beginning-of-class ()
  1462. "Move back to the open-curly that begin the enclosing class.
  1463. If point is outside a class, then move back to the
  1464. beginning of the prior class.
  1465. See also, `csharp-move-fwd-to-end-of-defun'."
  1466. (interactive)
  1467. (cond
  1468. ((bobp) nil)
  1469. (t
  1470. (let (found)
  1471. (save-excursion
  1472. ;; handle the case where we're at the top of a class now.
  1473. ;; if the user is asking to move back, then obviously
  1474. ;; he wants to move back to a *prior* defun.
  1475. (if (and (looking-at "{")
  1476. (looking-back (csharp--regexp 'class-start) nil)
  1477. (not (looking-back (csharp--regexp 'namespace-start) nil)))
  1478. (forward-char -1))
  1479. ;; now do the real work
  1480. (setq found (csharp--move-back-to-beginning-of-something
  1481. (csharp--regexp 'class-start)
  1482. (csharp--regexp 'namespace-start))))
  1483. (if found
  1484. (goto-char found))))))
  1485. (defun csharp-move-fwd-to-end-of-class ()
  1486. "Move forward to the close-curly that ends the enclosing class.
  1487. See also, `csharp-move-back-to-beginning-of-class'."
  1488. (interactive)
  1489. (let ((start (point))
  1490. dest-char)
  1491. (save-excursion
  1492. (csharp-move-back-to-beginning-of-class)
  1493. (forward-sexp)
  1494. (if (>= (point) start)
  1495. (setq dest-char (point))))
  1496. (if dest-char
  1497. (goto-char dest-char))))
  1498. (defun csharp-move-back-to-beginning-of-namespace ()
  1499. "Move back to the open-curly that begins the enclosing namespace.
  1500. If point is outside a namespace, then move back
  1501. to the beginning of the prior namespace."
  1502. (interactive)
  1503. (cond
  1504. ((bobp) nil)
  1505. (t
  1506. (let (found)
  1507. (save-excursion
  1508. ;; handle the case where we're at the top of a namespace now.
  1509. ;; if the user is asking to move back, then obviously
  1510. ;; he wants to move back to a *prior* defun.
  1511. (if (and (looking-at "{")
  1512. (looking-back (csharp--regexp 'namespace-start) nil))
  1513. (forward-char -1))
  1514. ;; now do the real work
  1515. (setq found (csharp--move-back-to-beginning-of-something
  1516. (csharp--regexp 'namespace-start))))
  1517. (if found
  1518. (goto-char found))))))
  1519. ;; moving
  1520. ;; ========================================================================
  1521. ;; ==================================================================
  1522. ;;; imenu stuff
  1523. (defconst csharp--imenu-expression
  1524. (let* ((single-space "[ \t\n\r\f\v]")
  1525. (optional-space (concat single-space "*"))
  1526. (bol "^[ \t]*") ;; BOL shouldnt accept lineshift.
  1527. (space (concat single-space "+"))
  1528. (access-modifier (regexp-opt '( "public" "private" "protected" "internal"
  1529. "static" "sealed" "partial" "override" "virtual"
  1530. "abstract" "async" "new" "unsafe")))
  1531. ;; this will allow syntactically invalid combinations of modifiers
  1532. ;; but that's a compiler problem, not a imenu-problem
  1533. (access-modifier-list (concat "\\(?:" access-modifier space "\\)"))
  1534. (access-modifiers (concat access-modifier-list "*"))
  1535. (basic-type (concat
  1536. ;; typename
  1537. "\\(?:[A-Za-z_][[:alnum:]_]*\\.\\)*"
  1538. "[A-Za-z_][[:alnum:]_]*"
  1539. ))
  1540. (type (concat
  1541. basic-type
  1542. ;; simplified, optional generic constraint.
  1543. ;; handles generic sub-types.
  1544. "\\(?:<[[:alnum:],<> \t\n\f\v\r]+>\\)?"))
  1545. (return-type (concat
  1546. type
  1547. ;; optional array-specifier
  1548. "\\(?:\\[\\]\\)?"))
  1549. (interface-prefix (concat "\\(?:" type "\\.\\)"))
  1550. ;; param-list with parens
  1551. (parameter-list "\\(?:\([^!\)]*\)\\)")
  1552. (inheritance-clause (concat "\\(?:"
  1553. optional-space
  1554. ":"
  1555. optional-space type
  1556. "\\(?:" optional-space "," optional-space type "\\)*"
  1557. "\\)?")))
  1558. (list (list "namespace"
  1559. (concat bol "namespace" space
  1560. "\\(" basic-type "\\)") 1)
  1561. ;; not all these are classes, but they can hold other
  1562. ;; members, so they are treated uniformly.
  1563. (list "class"
  1564. (concat bol
  1565. access-modifiers
  1566. "\\("
  1567. (regexp-opt '("class" "struct" "interface")) space
  1568. type inheritance-clause "\\)") 1)
  1569. (list "enum"
  1570. (concat bol
  1571. access-modifiers
  1572. "\\(" "enum" space
  1573. basic-type "\\)") 1)
  1574. (list "ctor"
  1575. (concat bol
  1576. ;; ctor MUST have access modifiers, or else we pick
  1577. ;; every if statement in the file...
  1578. access-modifier-list "+"
  1579. "\\("
  1580. basic-type
  1581. optional-space
  1582. parameter-list
  1583. "\\)"
  1584. "\\(?:"
  1585. optional-space
  1586. ":"
  1587. optional-space
  1588. "\\(?:this\\|base\\)"
  1589. optional-space
  1590. parameter-list
  1591. "\\)?"
  1592. optional-space "{") 1)
  1593. (list "method"
  1594. (concat bol
  1595. ;; we MUST require modifiers, or else we cannot reliably
  1596. ;; identify declarations, without also dragging in lots of
  1597. ;; if statements and what not.
  1598. access-modifier-list "+"
  1599. return-type space
  1600. "\\("
  1601. type
  1602. optional-space
  1603. parameter-list
  1604. "\\)"
  1605. ;; optional // or /* comment at end
  1606. "\\(?:[ \t]*/[/*].*\\)?"
  1607. optional-space
  1608. "{") 1)
  1609. (list "method-inf"
  1610. (concat bol
  1611. return-type space
  1612. "\\("
  1613. interface-prefix
  1614. type
  1615. optional-space
  1616. parameter-list
  1617. "\\)"
  1618. ;; optional // or /* comment at end
  1619. "\\(?:[ \t]*/[/*].*\\)?"
  1620. optional-space
  1621. "{") 1)
  1622. (list "method-abs-ext"
  1623. (concat bol
  1624. access-modifier-list "+"
  1625. (regexp-opt '("extern" "abstract")) space
  1626. return-type space
  1627. "\\("
  1628. type
  1629. optional-space
  1630. parameter-list
  1631. "\\)"
  1632. optional-space
  1633. ;; abstract/extern methods are terminated with ;
  1634. ";") 1)
  1635. ;; delegates are almost like abstract methods, so pick them up here
  1636. (list "delegate"
  1637. (concat bol
  1638. access-modifiers
  1639. "delegate" space
  1640. return-type space
  1641. "\\("
  1642. type
  1643. "\\)"
  1644. optional-space
  1645. parameter-list
  1646. ;; optional // or /* comment at end
  1647. optional-space
  1648. ";") 1)
  1649. (list "prop"
  1650. (concat bol
  1651. ;; must require access modifiers, or else we
  1652. ;; pick up pretty much anything.
  1653. access-modifiers
  1654. return-type space
  1655. "\\("
  1656. type
  1657. "\\)"
  1658. optional-space "{" optional-space
  1659. ;; unless we are super-specific and expect the accesors,
  1660. ;; lots of weird things gets slurped into the name.
  1661. ;; including the accessors themselves.
  1662. (regexp-opt '("get" "set"))
  1663. ) 1)
  1664. (list "prop-inf"
  1665. (concat bol
  1666. return-type space
  1667. "\\("
  1668. interface-prefix
  1669. type
  1670. "\\)"
  1671. optional-space "{" optional-space
  1672. ;; unless we are super-specific and expect the accesors,
  1673. ;; lots of weird things gets slurped into the name.
  1674. ;; including the accessors themselves.
  1675. (regexp-opt '("get" "set"))
  1676. ) 1)
  1677. ;; adding fields... too much?
  1678. (list "field"
  1679. (concat bol
  1680. access-modifier-list "+"
  1681. ;; fields can be readonly/const/volatile
  1682. "\\(?:" (regexp-opt '("readonly" "const" "volatile")) space "\\)?"
  1683. return-type space
  1684. "\\("
  1685. type
  1686. "\\)"
  1687. optional-space
  1688. ;; optional assignment
  1689. "\\(?:=[^;]+\\)?"
  1690. ";") 1)
  1691. (list "indexer"
  1692. (concat bol
  1693. access-modifiers
  1694. return-type space
  1695. "this" optional-space
  1696. "\\("
  1697. ;; opening bracket
  1698. "\\[" optional-space
  1699. ;; type
  1700. "\\([^\]]+\\)" optional-space
  1701. type
  1702. ;; closing brackets
  1703. "\\]"
  1704. "\\)"
  1705. optional-space "{" optional-space
  1706. ;; unless we are super-specific and expect the accesors,
  1707. ;; lots of weird things gets slurped into the name.
  1708. ;; including the accessors themselves.
  1709. (regexp-opt '("get" "set"))) 1)
  1710. (list "event"
  1711. (concat bol
  1712. access-modifier-list "+"
  1713. optional-space "event" optional-space
  1714. "\\("
  1715. return-type space
  1716. type
  1717. "\\)"
  1718. optional-space
  1719. ";") 1))))
  1720. (defun csharp--imenu-get-pos (pair)
  1721. "Return `position' from a (title . position) cons-pair `PAIR'.
  1722. The position may be a integer, or a marker (as returned by
  1723. imenu-indexing). This function ensures what is returned is an
  1724. integer which can be used for easy comparison."
  1725. (let ((pos (cdr pair)))
  1726. (if (markerp pos)
  1727. (marker-position pos)
  1728. pos)))
  1729. (defun csharp--imenu-get-container (item containers previous)
  1730. "Return the container which `ITEM' belongs to.
  1731. `ITEM' is a (title . position) cons-pair. `CONTAINERS' is a
  1732. list of such. `PREVIOUS' is the name of the previous
  1733. container found when recursing through `CONTAINERS'.
  1734. The final result is based on item's position relative to those
  1735. found in `CONTAINERS', or nil if none is found."
  1736. (if (not containers)
  1737. previous
  1738. (let* ((item-pos (csharp--imenu-get-pos item))
  1739. (container (car containers))
  1740. (container-pos (csharp--imenu-get-pos container))
  1741. (rest (cdr containers)))
  1742. (if (and container-pos
  1743. (< item-pos container-pos))
  1744. previous
  1745. (csharp--imenu-get-container item rest container)))))
  1746. (defun csharp--imenu-get-container-name (item containers)
  1747. "Return the name of the container which `ITEM' belongs to.
  1748. `ITEM' is a (title . position) cons-pair.
  1749. `CONTAINERS' is a list of such.
  1750. The name is based on the results from
  1751. `csharp--imenu-get-container'."
  1752. (let ((container (csharp--imenu-get-container item containers nil)))
  1753. (if (not container)
  1754. nil
  1755. (let ((container-p1 (car (split-string (car container)))) ;; namespace
  1756. (container-p2 (cadr (split-string (car container))))) ;; class/interface
  1757. ;; use p1 (namespace) when there is no p2
  1758. (if container-p2
  1759. container-p2
  1760. container-p1)))))
  1761. (defun csharp--imenu-sort (items)
  1762. "Sort an imenu-index list `ITEMS' by the string-portion."
  1763. (sort items (lambda (item1 item2)
  1764. (string< (car item1) (car item2)))))
  1765. (defun csharp--imenu-get-class-name (class namespaces)
  1766. "Gets a name for a imenu-index `CLASS'.
  1767. Result is based on its own name and `NAMESPACES' found in the same file."
  1768. (let ((namespace (csharp--imenu-get-container-name class namespaces))
  1769. (class-name (car class)))
  1770. (if (not namespace)
  1771. class-name
  1772. ;; reformat to include namespace
  1773. (let* ((words (split-string class-name))
  1774. (type (car words))
  1775. (name (cadr words)))
  1776. (concat type " " namespace "." name)))))
  1777. (defun csharp--imenu-get-class-nodes (classes namespaces)
  1778. "Create a new alist with CLASSES as root nodes with NAMESPACES added.
  1779. Each class will have one imenu index-entry \"( top)\" added by
  1780. default."
  1781. (mapcar (lambda (class)
  1782. (let ((class-name (csharp--imenu-get-class-name class namespaces))
  1783. (class-pos (cdr class)))
  1784. ;; construct a new alist-entry where value is itself
  1785. ;; a list of alist-entries with -1- entry which the top
  1786. ;; of the class itself.
  1787. (cons class-name
  1788. (list
  1789. (cons "( top )" class-pos)))))
  1790. classes))
  1791. (defun csharp--imenu-get-class-node (result item classes namespaces)
  1792. "Get the class-node in `RESULT' which an `ITEM' should be inserted into.
  1793. For this calculation, the original index items `CLASSES' and `NAMESPACES'
  1794. is needed."
  1795. (let* ((class-item (csharp--imenu-get-container item classes nil))
  1796. (class-name (csharp--imenu-get-class-name class-item namespaces)))
  1797. (assoc class-name result)))
  1798. (defun csharp--imenu-format-item-node (item type)
  1799. "Format an ITEM with a specified TYPE as an imenu item to be inserted into the index."
  1800. (cons
  1801. (concat "(" type ") " (car item))
  1802. (cdr item)))
  1803. (defun csharp--imenu-append-items-to-menu (result key name index classes namespaces)
  1804. "Formats the imenu-index using the provided values.
  1805. This is done by modifying the contents of `RESULT' in place."
  1806. ;; items = all methods, all events, etc based on "type"
  1807. (let* ((items (cdr (assoc key index))))
  1808. (dolist (item items)
  1809. (let ((class-node (csharp--imenu-get-class-node result item classes namespaces))
  1810. (item-node (csharp--imenu-format-item-node item name)))
  1811. (nconc class-node (list item-node))))))
  1812. (defun csharp--imenu-transform-index (index)
  1813. "Transform an imenu INDEX based on `IMENU-GENERIC-EXPRESSION'.
  1814. The resulting structure should be based on full type-names, with
  1815. type-members nested hierarchially below its parent.
  1816. See `csharp-mode-tests.el' for examples of expected behaviour
  1817. of such transformations."
  1818. (let* ((result nil)
  1819. (namespaces (cdr (assoc "namespace" index)))
  1820. (classes (cdr (assoc "class" index)))
  1821. (class-nodes (csharp--imenu-get-class-nodes classes namespaces)))
  1822. ;; be explicit about collection variable
  1823. (setq result class-nodes)
  1824. (dolist (type '(("ctor")
  1825. ("method")
  1826. ("method-inf" "method")
  1827. ("method-abs-ext" "method")
  1828. ("prop")
  1829. ("prop-inf" "prop")
  1830. ("field")
  1831. ("event")
  1832. ("indexer")))
  1833. (let* ((key (car type))
  1834. (name (car (last type))))
  1835. (csharp--imenu-append-items-to-menu result key name index classes namespaces)))
  1836. ;; add enums and delegates to main result list, as own items.
  1837. ;; We don't support nested types. EOS.
  1838. ;;
  1839. ;; This has the issue that they get reported as "function" in
  1840. ;; `helm-imenu', but there's nothing we can do about that.
  1841. ;; The alternative is making it a menu with -1- submenu which
  1842. ;; says "( top )" but that will be very clicky...
  1843. ;; before adding delegates, we need to pad the entry so that it
  1844. ;; matches the "<type> <name>" signature used by all the other
  1845. ;; imenu entries
  1846. (let ((delegates (cdr (assoc "delegate" index))))
  1847. (dolist (delegate delegates)
  1848. (setf (car delegate) (concat "delegate " (car delegate)))))
  1849. (dolist (type '("enum" "delegate"))
  1850. (dolist (item (cdr (assoc type index)))
  1851. (let ((item-name (csharp--imenu-get-class-name item namespaces)))
  1852. (setq result (cons (cons item-name (cdr item))
  1853. result)))))
  1854. ;; sort individual sub-lists
  1855. (dolist (item result)
  1856. (when (listp (cdr item))
  1857. (setf (cdr item) (csharp--imenu-sort (cdr item)))))
  1858. ;; sort main list
  1859. ;; (Enums always sort last though, because they dont have
  1860. ;; sub-menus)
  1861. (csharp--imenu-sort result)))
  1862. (defun csharp--imenu-create-index-function ()
  1863. "Create an imenu index."
  1864. (csharp--imenu-transform-index
  1865. (imenu--generic-function csharp--imenu-expression)))
  1866. (defun csharp--setup-imenu ()
  1867. "Set up `imenu' for `csharp-mode'."
  1868. ;; There are two ways to do imenu indexing. One is to provide a
  1869. ;; function, via `imenu-create-index-function'. The other is to
  1870. ;; provide imenu with a list of regexps via
  1871. ;; `imenu-generic-expression'; imenu will do a "generic scan" for you.
  1872. ;;
  1873. ;; We use both.
  1874. ;;
  1875. ;; First we use the `imenu-generic-expression' to build a index for
  1876. ;; us, but we do so inside a `imenu-create-index-function'
  1877. ;; implementation which allows us to tweak the results slightly
  1878. ;; before returning it to Emacs.
  1879. (setq imenu-create-index-function #'csharp--imenu-create-index-function)
  1880. (imenu-add-menubar-index))
  1881. ;; ==================================================================
  1882. ;; C# code-doc insertion magic
  1883. ;; ==================================================================
  1884. ;;
  1885. ;; In Visual Studio, if you type three slashes, it immediately expands into
  1886. ;; an inline code-documentation fragment. The following method does the
  1887. ;; same thing.
  1888. ;;
  1889. ;; This is the kind of thing that could be handled by YASnippet or
  1890. ;; another similarly flexible snippet framework. But I don't want to
  1891. ;; introduce a dependency on yasnippet to csharp-mode. So the capability
  1892. ;; must live within csharp-mode itself.
  1893. (defun csharp-maybe-insert-codedoc (arg)
  1894. "Insert an xml code documentation template on third consecutive slash.
  1895. This fn gets bound to / (the slash key), in
  1896. csharp-mode. If the slash being inserted is not the third
  1897. consecutive slash, the slash is inserted as normal. If it is the
  1898. third consecutive slash, then a xml code documentation template
  1899. may be inserted in some cases. For example,
  1900. a <summary> template is inserted if the prior line is empty,
  1901. or contains only an open curly brace;
  1902. a <remarks> template is inserted if the prior word
  1903. closes the <summary> element;
  1904. a <returns> template is inserted if the prior word
  1905. closes the <remarks> element;
  1906. an <example> template is inserted if the prior word closes
  1907. the <returns> element;
  1908. a <para> template is inserted if the prior word closes
  1909. a <para> element.
  1910. In all other cases the slash is inserted as normal.
  1911. The prefix argument ARG is passed on to `self-insert-command'
  1912. when the code documentation template isn't triggered. This makes
  1913. sure that M-10 / still produces 10 consecutive slashes as expected.
  1914. If you want the default cc-mode behavior, which implies no automatic
  1915. insertion of xml code documentation templates, then use this in
  1916. your `csharp-mode-hook' function:
  1917. (local-set-key (kbd \"/\") 'c-electric-slash)"
  1918. (interactive "*p")
  1919. ;;(message "csharp-maybe-insert-codedoc")
  1920. (let (
  1921. (cur-point (point))
  1922. (char last-command-event)
  1923. (cb0 (char-before (- (point) 0)))
  1924. (cb1 (char-before (- (point) 1)))
  1925. is-first-non-whitespace
  1926. did-auto-insert
  1927. )
  1928. ;; check if two prior chars were slash, in other words,
  1929. ;; check if this is the third slash in a row.
  1930. (if (and (= char ?/) cb0 (= ?/ cb0) cb1 (= ?/ cb1))
  1931. (progn
  1932. ;;(message "yes - this is the third consecutive slash")
  1933. (setq is-first-non-whitespace
  1934. (save-excursion
  1935. (back-to-indentation)
  1936. (= cur-point (+ (point) 2))))
  1937. (if is-first-non-whitespace
  1938. ;; This is a 3-slash sequence. It is the first non-whitespace text
  1939. ;; on the line. Now we need to examine the surrounding context
  1940. ;; in order to determine which xml cod doc template to insert.
  1941. (let (word-back char0 char1
  1942. word-fore char-0 char-1
  1943. text-to-insert ;; text to insert in lieu of slash
  1944. fn-to-call ;; func to call after inserting text
  1945. (preceding-line-is-empty (or
  1946. (= (line-number-at-pos) 1)
  1947. (save-excursion
  1948. (forward-line -1)
  1949. (beginning-of-line)
  1950. (looking-at "[ \t]*$\\|[ \t]*{[ \t]*$"))))
  1951. (flavor 0) ;; used only for diagnostic purposes
  1952. )
  1953. ;;(message "starting a 3-slash comment")
  1954. ;; get the prior word, and the 2 chars preceding it.
  1955. (backward-word)
  1956. (setq word-back (thing-at-point 'word)
  1957. char0 (char-before (- (point) 0))
  1958. char1 (char-before (- (point) 1)))
  1959. ;; restore prior position
  1960. (goto-char cur-point)
  1961. ;; get the following word, and the 2 chars preceding it.
  1962. (forward-word)
  1963. (backward-word)
  1964. (setq word-fore (thing-at-point 'word)
  1965. char-0 (char-before (- (point) 0))
  1966. char-1 (char-before (- (point) 1)))
  1967. ;; restore prior position again
  1968. (goto-char cur-point)
  1969. (cond
  1970. ;; The preceding line is empty, or all whitespace, or
  1971. ;; contains only an open-curly. In this case, insert a
  1972. ;; summary element pair.
  1973. (preceding-line-is-empty
  1974. (setq text-to-insert "/ <summary>\n /// \n /// </summary>"
  1975. flavor 1) )
  1976. ;; The preceding word closed a summary element. In this case,
  1977. ;; if the forward word does not open a remarks element, then
  1978. ;; insert a remarks element.
  1979. ((and (string-equal word-back "summary") (eq char0 ?/) (eq char1 ?<))
  1980. (if (not (and (string-equal word-fore "remarks") (eq char-0 ?<)))
  1981. (setq text-to-insert "/ <remarks>\n /// <para>\n /// \n /// </para>\n /// </remarks>"
  1982. flavor 2)))
  1983. ;; The preceding word closed the remarks section. In this case,
  1984. ;; insert an example element.
  1985. ((and (string-equal word-back "remarks") (eq char0 ?/) (eq char1 ?<))
  1986. (setq text-to-insert "/ <example>\n /// \n /// </example>"
  1987. flavor 3))
  1988. ;; The preceding word closed the example section. In this
  1989. ;; case, insert an returns element. This isn't always
  1990. ;; correct, because sometimes the xml code doc is attached to
  1991. ;; a class or a property, neither of which has a return
  1992. ;; value. A more intelligent implementation would inspect the
  1993. ;; syntax state and only inject a returns element if
  1994. ;; appropriate.
  1995. ((and (string-equal word-back "example") (eq char0 ?/) (eq char1 ?<))
  1996. (setq text-to-insert "/ <returns></returns>"
  1997. fn-to-call (lambda ()
  1998. (backward-word)
  1999. (backward-char)
  2000. (backward-char)
  2001. (c-indent-line-or-region)
  2002. )
  2003. flavor 4))
  2004. ;; The preceding word opened the remarks section, or it
  2005. ;; closed a para section. In this case, insert a para
  2006. ;; element, using appropriate indentation with respect to the
  2007. ;; prior tag.
  2008. ((or
  2009. (and (string-equal word-back "remarks") (eq char0 ?<) (or (eq char1 32) (eq char1 9)))
  2010. (and (string-equal word-back "para") (eq char0 ?/) (eq char1 ?<)))
  2011. (let (prior-point spacer)
  2012. (save-excursion
  2013. (backward-word)
  2014. (backward-char)
  2015. (backward-char)
  2016. (setq prior-point (point))
  2017. (skip-chars-backward "\t ")
  2018. (setq spacer (buffer-substring (point) prior-point))
  2019. ;;(message (format "pt(%d) prior(%d) spacer(%s)" (point) prior-point spacer))
  2020. )
  2021. (if (string-equal word-back "remarks")
  2022. (setq spacer (concat spacer " ")))
  2023. (setq text-to-insert (format "/%s<para>\n ///%s \n ///%s</para>"
  2024. spacer spacer spacer)
  2025. flavor 6)))
  2026. ;; The preceding word opened a para element. In this case, if
  2027. ;; the forward word does not close the para element, then
  2028. ;; close the para element.
  2029. ;; --
  2030. ;; This is a nice idea but flawed. Suppose I have a para element with some
  2031. ;; text in it. If I position the cursor at the first line, then type 3 slashes,
  2032. ;; I get a close-element, and that would be inappropriate. Not sure I can
  2033. ;; easily solve that problem, so the best thing might be to simply punt, and
  2034. ;; require people to close their own elements.
  2035. ;;
  2036. ;; ( (and (string-equal word-back "para") (eq char0 60) (or (eq char1 32) (eq char1 9)))
  2037. ;; (if (not (and (string-equal word-fore "para") (eq char-0 47) (eq char-1 60) ))
  2038. ;; (setq text-to-insert "/ \n/// </para>\n///"
  2039. ;; fn-to-call (lambda ()
  2040. ;; (previous-line)
  2041. ;; (end-of-line)
  2042. ;; )
  2043. ;; flavor 7) )
  2044. ;; )
  2045. ;; the default case - do nothing
  2046. (t nil))
  2047. (if text-to-insert
  2048. (progn
  2049. ;;(message (format "inserting special text (f(%d))" flavor))
  2050. ;; set the flag, that we actually inserted text
  2051. (setq did-auto-insert t)
  2052. ;; save point of beginning of insertion
  2053. (setq cur-point (point))
  2054. ;; actually insert the text
  2055. (insert text-to-insert)
  2056. ;; indent the inserted string, and re-position point, either through
  2057. ;; the case-specific fn, or via the default progn.
  2058. (if fn-to-call
  2059. (funcall fn-to-call)
  2060. (let ((newline-count 0) (pos 0) ix)
  2061. ;; count the number of newlines in the inserted string
  2062. (while (string-match "\n" text-to-insert pos)
  2063. (setq pos (match-end 0)
  2064. newline-count (+ newline-count 1) )
  2065. )
  2066. ;; indent what we just inserted
  2067. (c-indent-region cur-point (point) t)
  2068. ;; move up n/2 lines. This assumes that the
  2069. ;; inserted text is ~symmetric about the halfway point.
  2070. ;; The assumption holds if the xml code doc uses a
  2071. ;; begin-elt and end-elt on a new line all by themselves,
  2072. ;; and a blank line in between them where the point should be.
  2073. ;; A more intelligent implementation would use a specific
  2074. ;; marker string, like @@DOT, to note the desired point.
  2075. (forward-line (- 0 (/ newline-count 2)))
  2076. (end-of-line)))))))))
  2077. (if (not did-auto-insert)
  2078. (self-insert-command (prefix-numeric-value arg)))))
  2079. ;; ==================================================================
  2080. ;; end of c# code-doc insertion magic
  2081. ;; ==================================================================
  2082. (defun csharp-time ()
  2083. "Return the time of day as a string. Used in the `csharp-log' function."
  2084. (substring (current-time-string) 11 19)) ;24-hr time
  2085. (defun csharp-log (level text &rest args)
  2086. "Log a message at level LEVEL.
  2087. If LEVEL is higher than `csharp-log-level', the message is
  2088. ignored. Otherwise, it is printed using `message'.
  2089. TEXT is a format control string, and the remaining arguments ARGS
  2090. are the string substitutions (see `format')."
  2091. (if (<= level csharp-log-level)
  2092. (let* ((msg (apply 'format text args)))
  2093. (message "C# %s %s" (csharp-time) msg))))
  2094. ;; ==================================================================
  2095. ;; C#-specific optimizations of cc-mode funcs
  2096. ;; ==================================================================
  2097. ;; There's never a need to move over an Obj-C directive in csharp-mode.
  2098. (defadvice c-forward-objc-directive (around
  2099. csharp-mode-advice-2
  2100. compile activate)
  2101. "Make `c-forward-objc-directive' a no-op in `csharp-mode'."
  2102. (if (c-major-mode-is 'csharp-mode)
  2103. nil
  2104. ad-do-it)
  2105. )
  2106. ;; ==================================================================
  2107. ;; end of C#-specific optimizations of cc-mode funcs
  2108. ;; ==================================================================
  2109. ;; ==================================================================
  2110. ;; c# - monkey-patching of basic parsing logic
  2111. ;; ==================================================================
  2112. ;;
  2113. ;; The following 2 defuns redefine functions from cc-mode, to add
  2114. ;; special cases for C#. These primarily deal with indentation of
  2115. ;; instance initializers, which are somewhat unique to C#. I couldn't
  2116. ;; figure out how to get cc-mode to do what C# needs, without modifying
  2117. ;; these defuns.
  2118. ;;
  2119. ;; verabatim copy of c-font-lock-invalid-string before it was removed
  2120. ;; from emacs/cc-mode in Git commit bb591f139f0602af292c772f974dcc14dabb1deb.
  2121. (defun csharp-mode-font-lock-invalid-string ()
  2122. ;; Assuming the point is after the opening character of a string,
  2123. ;; fontify that char with `font-lock-warning-face' if the string
  2124. ;; decidedly isn't terminated properly.
  2125. ;;
  2126. ;; This function does hidden buffer changes.
  2127. (let ((start (1- (point))))
  2128. (save-excursion
  2129. (and (eq (elt (parse-partial-sexp start (c-point 'eol)) 8) start)
  2130. (if (if (eval-when-compile (integerp ?c))
  2131. ;; Emacs
  2132. (integerp c-multiline-string-start-char)
  2133. ;; XEmacs
  2134. (characterp c-multiline-string-start-char))
  2135. ;; There's no multiline string start char before the
  2136. ;; string, so newlines aren't allowed.
  2137. (not (eq (char-before start) c-multiline-string-start-char))
  2138. ;; Multiline strings are allowed anywhere if
  2139. ;; c-multiline-string-start-char is t.
  2140. (not c-multiline-string-start-char))
  2141. (if c-string-escaped-newlines
  2142. ;; There's no \ before the newline.
  2143. (not (eq (char-before (point)) ?\\))
  2144. ;; Escaped newlines aren't supported.
  2145. t)
  2146. (c-put-font-lock-face start (1+ start) 'font-lock-warning-face)))))
  2147. (advice-add 'c-looking-at-inexpr-block
  2148. :around 'csharp--c-looking-at-inexpr-block-hack)
  2149. (defun csharp--c-looking-at-inexpr-block-hack (orig-fun &rest args)
  2150. (apply
  2151. (if (eq major-mode 'csharp-mode)
  2152. #'csharp--c-looking-at-inexpr-block
  2153. orig-fun)
  2154. args))
  2155. (defun csharp--c-looking-at-inexpr-block (lim containing-sexp &optional check-at-end)
  2156. ;; Return non-nil if we're looking at the beginning of a block
  2157. ;; inside an expression. The value returned is actually a cons of
  2158. ;; either 'inlambda, 'inexpr-statement or 'inexpr-class and the
  2159. ;; position of the beginning of the construct.
  2160. ;;
  2161. ;; LIM limits the backward search. CONTAINING-SEXP is the start
  2162. ;; position of the closest containing list. If it's nil, the
  2163. ;; containing paren isn't used to decide whether we're inside an
  2164. ;; expression or not. If both LIM and CONTAINING-SEXP are used, LIM
  2165. ;; needs to be farther back.
  2166. ;;
  2167. ;; If CHECK-AT-END is non-nil then extra checks at the end of the
  2168. ;; brace block might be done. It should only be used when the
  2169. ;; construct can be assumed to be complete, i.e. when the original
  2170. ;; starting position was further down than that.
  2171. ;;
  2172. ;; This function might do hidden buffer changes.
  2173. (save-excursion
  2174. (let ((res 'maybe) passed-paren
  2175. (closest-lim (or containing-sexp lim (point-min)))
  2176. ;; Look at the character after point only as a last resort
  2177. ;; when we can't disambiguate.
  2178. (block-follows (and (eq (char-after) ?{) (point))))
  2179. (while (and (eq res 'maybe)
  2180. (progn (c-backward-syntactic-ws)
  2181. (> (point) closest-lim))
  2182. (not (bobp))
  2183. (progn (backward-char)
  2184. (looking-at "[\]\).]\\|\w\\|\\s_"))
  2185. (c-safe (forward-char)
  2186. (goto-char (scan-sexps (point) -1))))
  2187. (setq res
  2188. (if (looking-at c-keywords-regexp)
  2189. (let ((kw-sym (c-keyword-sym (match-string 1))))
  2190. (cond
  2191. ((and block-follows
  2192. (c-keyword-member kw-sym 'c-inexpr-class-kwds))
  2193. (and (not (eq passed-paren ?\[))
  2194. ;; dinoch Thu, 22 Apr 2010 18:20
  2195. ;; ============================================
  2196. ;; looking at new MyType() { ... }
  2197. ;; means this is a brace list, so, return nil,
  2198. ;; implying NOT looking-at-inexpr-block
  2199. (not
  2200. (and (c-major-mode-is 'csharp-mode)
  2201. (looking-at "new[ \t\n\f\v\r]+\\([[:alnum:]_]+\\)\\b")))
  2202. (or (not (looking-at c-class-key))
  2203. ;; If the class instantiation is at the start of
  2204. ;; a statement, we don't consider it an
  2205. ;; in-expression class.
  2206. (let ((prev (point)))
  2207. (while (and
  2208. (= (c-backward-token-2 1 nil closest-lim) 0)
  2209. (eq (char-syntax (char-after)) ?w))
  2210. (setq prev (point)))
  2211. (goto-char prev)
  2212. (not (c-at-statement-start-p)))
  2213. ;; Also, in Pike we treat it as an
  2214. ;; in-expression class if it's used in an
  2215. ;; object clone expression.
  2216. (save-excursion
  2217. (and check-at-end
  2218. (c-major-mode-is 'pike-mode)
  2219. (progn (goto-char block-follows)
  2220. (zerop (c-forward-token-2 1 t)))
  2221. (eq (char-after) ?\())))
  2222. (cons 'inexpr-class (point))))
  2223. ((c-keyword-member kw-sym 'c-inexpr-block-kwds)
  2224. (when (not passed-paren)
  2225. (cons 'inexpr-statement (point))))
  2226. ((c-keyword-member kw-sym 'c-lambda-kwds)
  2227. (when (or (not passed-paren)
  2228. (eq passed-paren ?\())
  2229. (cons 'inlambda (point))))
  2230. ((c-keyword-member kw-sym 'c-block-stmt-kwds)
  2231. nil)
  2232. (t
  2233. 'maybe)))
  2234. (if (looking-at "\\s(")
  2235. (if passed-paren
  2236. (if (and (eq passed-paren ?\[)
  2237. (eq (char-after) ?\[))
  2238. ;; Accept several square bracket sexps for
  2239. ;; Java array initializations.
  2240. 'maybe)
  2241. (setq passed-paren (char-after))
  2242. 'maybe)
  2243. 'maybe))))
  2244. (if (eq res 'maybe)
  2245. (when (and c-recognize-paren-inexpr-blocks
  2246. block-follows
  2247. containing-sexp
  2248. (eq (char-after containing-sexp) ?\())
  2249. (goto-char containing-sexp)
  2250. (if (or (save-excursion
  2251. (c-backward-syntactic-ws lim)
  2252. (and (> (point) (or lim (point-min)))
  2253. (c-on-identifier)))
  2254. (and c-special-brace-lists
  2255. (c-looking-at-special-brace-list)))
  2256. nil
  2257. (cons 'inexpr-statement (point))))
  2258. res))))
  2259. (advice-add 'c-inside-bracelist-p
  2260. :around 'csharp-inside-bracelist-or-c-inside-bracelist-p)
  2261. (defun csharp-inside-bracelist-or-c-inside-bracelist-p (command &rest args)
  2262. "Run `csharp-inside-bracelist-p' if in `csharp-mode'.
  2263. Otherwise run `c-inside-bracelist-p'."
  2264. (if (eq major-mode 'csharp-mode)
  2265. (csharp-inside-bracelist-p (nth 0 args) (nth 1 args))
  2266. (apply command args)))
  2267. (defun csharp-inside-bracelist-p (containing-sexp paren-state)
  2268. ;; return the buffer position of the beginning of the brace list
  2269. ;; statement if we're inside a brace list, otherwise return nil.
  2270. ;; CONTAINING-SEXP is the buffer pos of the innermost containing
  2271. ;; paren. PAREN-STATE is the remainder of the state of enclosing
  2272. ;; braces
  2273. ;;
  2274. ;; N.B.: This algorithm can potentially get confused by cpp macros
  2275. ;; placed in inconvenient locations. It's a trade-off we make for
  2276. ;; speed.
  2277. ;;
  2278. ;; This function might do hidden buffer changes.
  2279. (or
  2280. ;; This will pick up brace list declarations.
  2281. (c-safe
  2282. (save-excursion
  2283. (goto-char containing-sexp)
  2284. (c-safe (c-forward-sexp -1))
  2285. (let (bracepos)
  2286. (if (and (or (looking-at c-brace-list-key)
  2287. (progn
  2288. (c-safe (c-forward-sexp -1))
  2289. (looking-at c-brace-list-key))
  2290. (and (c-major-mode-is 'csharp-mode)
  2291. (or
  2292. ;; dinoch Thu, 22 Apr 2010 18:20
  2293. ;; ============================================
  2294. ;; looking enum Foo : int
  2295. ;; means this is a brace list, so, return nil,
  2296. ;; implying NOT looking-at-inexpr-block
  2297. (progn
  2298. (c-safe (c-forward-sexp -1))
  2299. (looking-at csharp-enum-decl-re))
  2300. ;; type-initializers are not properly detected and
  2301. ;; indented unless we help out. (no need to forward
  2302. ;; when looking here, because enum-check already did
  2303. ;; it!)
  2304. (looking-at csharp-type-initializer-statement-re))))
  2305. (setq bracepos (c-down-list-forward (point)))
  2306. (or
  2307. (not (c-crosses-statement-barrier-p (point)
  2308. (- bracepos 2)))
  2309. ;; this little hack (combined with the regexp-check above)
  2310. ;; fixes indentation for all type-initializers.
  2311. (c-major-mode-is 'csharp-mode)))
  2312. (point)))))
  2313. ;; this will pick up array/aggregate init lists, even if they are nested.
  2314. (save-excursion
  2315. (let ((class-key
  2316. ;; Pike can have class definitions anywhere, so we must
  2317. ;; check for the class key here.
  2318. (and (c-major-mode-is 'pike-mode)
  2319. c-decl-block-key))
  2320. bufpos braceassignp lim next-containing)
  2321. (while (and (not bufpos)
  2322. containing-sexp)
  2323. (when paren-state
  2324. (if (consp (car paren-state))
  2325. (setq lim (cdr (car paren-state))
  2326. paren-state (cdr paren-state))
  2327. (setq lim (car paren-state)))
  2328. (when paren-state
  2329. (setq next-containing (car paren-state)
  2330. paren-state (cdr paren-state))))
  2331. (goto-char containing-sexp)
  2332. (if (c-looking-at-inexpr-block next-containing next-containing)
  2333. ;; We're in an in-expression block of some kind. Do not
  2334. ;; check nesting. We deliberately set the limit to the
  2335. ;; containing sexp, so that c-looking-at-inexpr-block
  2336. ;; doesn't check for an identifier before it.
  2337. (setq containing-sexp nil)
  2338. ;; see if the open brace is preceded by = or [...] in
  2339. ;; this statement, but watch out for operator=
  2340. (setq braceassignp 'dontknow)
  2341. (c-backward-token-2 1 t lim)
  2342. ;; Checks to do only on the first sexp before the brace.
  2343. (when (and c-opt-inexpr-brace-list-key
  2344. (eq (char-after) ?\[))
  2345. ;; In Java, an initialization brace list may follow
  2346. ;; directly after "new Foo[]", so check for a "new"
  2347. ;; earlier.
  2348. (while (eq braceassignp 'dontknow)
  2349. (setq braceassignp
  2350. (cond ((/= (c-backward-token-2 1 t lim) 0) nil)
  2351. ((looking-at c-opt-inexpr-brace-list-key) t)
  2352. ((looking-at "\\sw\\|\\s_\\|[.[]")
  2353. ;; Carry on looking if this is an
  2354. ;; identifier (may contain "." in Java)
  2355. ;; or another "[]" sexp.
  2356. 'dontknow)
  2357. (t nil)))))
  2358. ;; Checks to do on all sexps before the brace, up to the
  2359. ;; beginning of the statement.
  2360. (while (eq braceassignp 'dontknow)
  2361. (cond ((eq (char-after) ?\;)
  2362. (setq braceassignp nil))
  2363. ((and class-key
  2364. (looking-at class-key))
  2365. (setq braceassignp nil))
  2366. ((eq (char-after) ?=)
  2367. ;; We've seen a =, but must check earlier tokens so
  2368. ;; that it isn't something that should be ignored.
  2369. (setq braceassignp 'maybe)
  2370. (while (and (eq braceassignp 'maybe)
  2371. (zerop (c-backward-token-2 1 t lim)))
  2372. (setq braceassignp
  2373. (cond
  2374. ;; Check for operator =
  2375. ((and c-opt-op-identifier-prefix
  2376. (looking-at c-opt-op-identifier-prefix))
  2377. nil)
  2378. ;; Check for `<opchar>= in Pike.
  2379. ((and (c-major-mode-is 'pike-mode)
  2380. (or (eq (char-after) ?`)
  2381. ;; Special case for Pikes
  2382. ;; `[]=, since '[' is not in
  2383. ;; the punctuation class.
  2384. (and (eq (char-after) ?\[)
  2385. (eq (char-before) ?`))))
  2386. nil)
  2387. ((looking-at "\\s.") 'maybe)
  2388. ;; make sure we're not in a C++ template
  2389. ;; argument assignment
  2390. ((and
  2391. (c-major-mode-is 'c++-mode)
  2392. (save-excursion
  2393. (let ((here (point))
  2394. (pos< (progn
  2395. (skip-chars-backward "^<>")
  2396. (point))))
  2397. (and (eq (char-before) ?<)
  2398. (not (c-crosses-statement-barrier-p
  2399. pos< here))
  2400. (not (c-in-literal))
  2401. ))))
  2402. nil)
  2403. (t t))))))
  2404. (if (and (eq braceassignp 'dontknow)
  2405. (/= (c-backward-token-2 1 t lim) 0))
  2406. (setq braceassignp nil)))
  2407. (if (not braceassignp)
  2408. (if (eq (char-after) ?\;)
  2409. ;; Brace lists can't contain a semicolon, so we're done.
  2410. (setq containing-sexp nil)
  2411. ;; Go up one level.
  2412. (setq containing-sexp next-containing
  2413. lim nil
  2414. next-containing nil))
  2415. ;; we've hit the beginning of the aggregate list
  2416. (c-beginning-of-statement-1
  2417. (c-most-enclosing-brace paren-state))
  2418. (setq bufpos (point))))
  2419. )
  2420. bufpos))
  2421. ))
  2422. ;; ==================================================================
  2423. ;; end of monkey-patching of basic parsing logic
  2424. ;; ==================================================================
  2425. ;;(easy-menu-define csharp-menu csharp-mode-map "C# Mode Commands"
  2426. ;; ;; Can use `csharp' as the language for `c-mode-menu'
  2427. ;; ;; since its definition covers any language. In
  2428. ;; ;; this case the language is used to adapt to the
  2429. ;; ;; nonexistence of a cpp pass and thus removing some
  2430. ;; ;; irrelevant menu alternatives.
  2431. ;; (cons "C#" (c-lang-const c-mode-menu csharp)))
  2432. ;;; Compilation regexps
  2433. ;; When invoked by MSBuild, csc’s errors look like this:
  2434. ;; subfolder\file.cs(6,18): error CS1006: Name of constructor must
  2435. ;; match name of class [c:\Users\user\project.csproj]
  2436. (defun csharp--compilation-error-file-resolve ()
  2437. "Resolve an msbuild error to a (filename . dirname) cons cell."
  2438. ;; http://stackoverflow.com/a/18049590/429091
  2439. (cons (match-string 1) (file-name-directory (match-string 4))))
  2440. (defconst csharp-compilation-re-msbuild-error
  2441. (concat
  2442. "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
  2443. "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): "
  2444. "error [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$")
  2445. "Regexp to match compilation error from msbuild.")
  2446. (defconst csharp-compilation-re-msbuild-warning
  2447. (concat
  2448. "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
  2449. "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): "
  2450. "warning [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$")
  2451. "Regexp to match compilation warning from msbuild.")
  2452. ;; Notes on xbuild and devenv commonalities
  2453. ;;
  2454. ;; These regexes were tailored for xbuild, but apart from the concurrent
  2455. ;; build-marker ("1>") they share exactly the same match-markers.
  2456. ;;
  2457. ;; If we don't exclude the match-markers explicitly, these regexes
  2458. ;; will also be used to match for devenv as well, including the build-marker
  2459. ;; in the file-name, causing the lookup to fail.
  2460. ;;
  2461. ;; So if we don't want devenv to fail, we actually need to handle it in our
  2462. ;; xbuild-regexes, but then we automatically get devenv-support for free.
  2463. (defconst csharp-compilation-re-xbuild-error
  2464. (concat
  2465. "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
  2466. "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?"
  2467. ;; handle weird devenv output format with 4 numbers, not 2 by having optional
  2468. ;; extra capture-groups.
  2469. "\\(?:,\\([0-9]+\\)\\)*): "
  2470. "error [[:alnum:]]+: .+$")
  2471. "Regexp to match compilation error from xbuild.")
  2472. (defconst csharp-compilation-re-xbuild-warning
  2473. (concat
  2474. "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?"
  2475. "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?"
  2476. ;; handle weird devenv output format with 4 numbers, not 2 by having optional
  2477. ;; extra capture-groups.
  2478. "\\(?:,\\([0-9]+\\)\\)?*): "
  2479. "warning [[:alnum:]]+: .+$")
  2480. "Regexp to match compilation warning from xbuild.")
  2481. (eval-after-load 'compile
  2482. (lambda ()
  2483. (dolist
  2484. (regexp
  2485. `((xbuild-error
  2486. ,csharp-compilation-re-xbuild-error
  2487. 1 2 3 2)
  2488. (xbuild-warning
  2489. ,csharp-compilation-re-xbuild-warning
  2490. 1 2 3 1)
  2491. (msbuild-error
  2492. ,csharp-compilation-re-msbuild-error
  2493. csharp--compilation-error-file-resolve
  2494. 2
  2495. 3
  2496. 2
  2497. nil
  2498. (1 compilation-error-face)
  2499. (4 compilation-error-face))
  2500. (msbuild-warning
  2501. ,csharp-compilation-re-msbuild-warning
  2502. csharp--compilation-error-file-resolve
  2503. 2
  2504. 3
  2505. 1
  2506. nil
  2507. (1 compilation-warning-face)
  2508. (4 compilation-warning-face))))
  2509. (add-to-list 'compilation-error-regexp-alist-alist regexp)
  2510. (add-to-list 'compilation-error-regexp-alist (car regexp)))))
  2511. ;;; Autoload mode trigger
  2512. ;;;###autoload
  2513. (add-to-list 'auto-mode-alist '("\\.cs$" . csharp-mode))
  2514. (c-add-style "C#"
  2515. '("Java"
  2516. (c-basic-offset . 4)
  2517. (c-comment-only-line-offset . (0 . 0))
  2518. (c-offsets-alist . (
  2519. (access-label . -)
  2520. (arglist-close . c-lineup-arglist)
  2521. (arglist-cont . 0)
  2522. (arglist-cont-nonempty . c-lineup-arglist)
  2523. (arglist-intro . c-lineup-arglist-intro-after-paren)
  2524. (block-close . 0)
  2525. (block-open . 0)
  2526. (brace-entry-open . 0)
  2527. (brace-list-close . 0)
  2528. (brace-list-entry . 0)
  2529. (brace-list-intro . +)
  2530. (brace-list-open . 0)
  2531. (c . c-lineup-C-comments)
  2532. (case-label . +)
  2533. (catch-clause . 0)
  2534. (class-close . 0)
  2535. (class-open . 0)
  2536. (comment-intro . c-lineup-comment)
  2537. (cpp-macro . [0])
  2538. (cpp-macro-cont . c-lineup-dont-change)
  2539. (defun-block-intro . +)
  2540. (defun-close . 0)
  2541. (defun-open . 0)
  2542. (do-while-closure . 0)
  2543. (else-clause . 0)
  2544. (extern-lang-close . 0)
  2545. (extern-lang-open . 0)
  2546. (friend . 0)
  2547. (func-decl-cont . +)
  2548. (inclass . +)
  2549. (inexpr-class . 0)
  2550. (inexpr-statement . 0)
  2551. (inextern-lang . +)
  2552. (inher-cont . c-lineup-multi-inher)
  2553. (inher-intro . +)
  2554. (inlambda . c-lineup-inexpr-block)
  2555. (inline-close . 0)
  2556. (inline-open . 0)
  2557. (innamespace . +)
  2558. (knr-argdecl . 0)
  2559. (knr-argdecl-intro . 5)
  2560. (label . 0)
  2561. (lambda-intro-cont . +)
  2562. (member-init-cont . c-lineup-multi-inher)
  2563. (member-init-intro . +)
  2564. (namespace-close . 0)
  2565. (namespace-open . 0)
  2566. (statement . 0)
  2567. (statement-block-intro . +)
  2568. (statement-case-intro . +)
  2569. (statement-case-open . +)
  2570. (statement-cont . +)
  2571. (stream-op . c-lineup-streamop)
  2572. (string . c-lineup-dont-change)
  2573. (substatement . +)
  2574. (substatement-open . 0)
  2575. (template-args-cont c-lineup-template-args +)
  2576. (topmost-intro . 0)
  2577. (topmost-intro-cont . +)
  2578. ))
  2579. ))
  2580. ;;;###autoload
  2581. (define-derived-mode csharp-mode prog-mode "C#"
  2582. "Major mode for editing C# code.
  2583. The mode provides fontification and indent for C# syntax, as well
  2584. as some other handy features.
  2585. At mode startup, there are two interesting hooks that run:
  2586. `prog-mode-hook' is run with no args, then `csharp-mode-hook' is run after
  2587. that, also with no args.
  2588. To run your own logic after csharp-mode starts, do this:
  2589. (defun my-csharp-mode-fn ()
  2590. \"my function that runs when csharp-mode is initialized for a buffer.\"
  2591. (turn-on-font-lock)
  2592. (turn-on-auto-revert-mode) ;; helpful when also using Visual Studio
  2593. (setq indent-tabs-mode nil) ;; tabs are evil
  2594. ....your own code here...
  2595. )
  2596. (add-hook 'csharp-mode-hook 'my-csharp-mode-fn t)
  2597. The function above is just a suggestion.
  2598. Imenu Integration
  2599. ===============================
  2600. Check the menubar for menu entries for Imenu; it is labelled
  2601. \"Index\".
  2602. The Imenu index gets computed when the file is .cs first opened and loaded.
  2603. This may take a moment or two. If you don't like this delay and don't
  2604. use Imenu, you can turn this off with the variable `csharp-want-imenu'.
  2605. Key bindings:
  2606. \\{csharp-mode-map}"
  2607. (make-local-variable 'beginning-of-defun-function)
  2608. (make-local-variable 'end-of-defun-function)
  2609. (c-initialize-cc-mode t)
  2610. ;; define underscore as part of a word in the Csharp syntax table
  2611. (modify-syntax-entry ?_ "w" csharp-mode-syntax-table)
  2612. ;; define @ as an expression prefix in Csharp syntax table
  2613. (modify-syntax-entry ?@ "'" csharp-mode-syntax-table)
  2614. ;; `c-init-language-vars' is a macro that is expanded at compile
  2615. ;; time to a large `setq' with all the language variables and their
  2616. ;; customized values for our language.
  2617. (c-init-language-vars csharp-mode)
  2618. ;; Use our predefined "C#" style unless a file local or default
  2619. ;; style is found. This is done by rebinding `c-default-style'
  2620. ;; during the `c-common-init' call. 'c-common-init' will initialize
  2621. ;; the buffer's style using the value of `c-default-style'.
  2622. (let ((c-default-style (if (or c-file-style
  2623. (stringp c-default-style)
  2624. (assq 'csharp-mode c-default-style))
  2625. c-default-style
  2626. "C#")))
  2627. ;; `c-common-init' initializes most of the components of a CC Mode
  2628. ;; buffer, including setup of the mode menu, font-lock, etc.
  2629. ;; There's also a lower level routine `c-basic-common-init' that
  2630. ;; only makes the necessary initialization to get the syntactic
  2631. ;; analysis and similar things working.
  2632. (c-common-init 'csharp-mode))
  2633. (define-key csharp-mode-map (kbd "/") 'csharp-maybe-insert-codedoc)
  2634. ;; Need the following for parse-partial-sexp to work properly with
  2635. ;; verbatim literal strings Setting this var to non-nil tells
  2636. ;; `parse-partial-sexp' to pay attention to the syntax text
  2637. ;; properties on the text in the buffer. If csharp-mode attaches
  2638. ;; text syntax to @"..." then, `parse-partial-sexp' will treat those
  2639. ;; strings accordingly.
  2640. (set (make-local-variable 'parse-sexp-lookup-properties) t)
  2641. ;; Allow fill-paragraph to work on xml code doc
  2642. ;; This setting gets overwritten quietly by c-run-mode-hooks,
  2643. ;; so I put it afterwards to make it stick.
  2644. (make-local-variable 'paragraph-separate)
  2645. ;; Speedbar handling
  2646. (when (fboundp 'speedbar-add-supported-extension)
  2647. (speedbar-add-supported-extension '(".cs"))) ;; idempotent
  2648. (c-update-modeline)
  2649. ;; maybe do imenu scan after hook returns
  2650. (when csharp-want-imenu
  2651. (csharp--setup-imenu))
  2652. ;; The paragraph-separate variable was getting stomped by
  2653. ;; other hooks, so it must reside here.
  2654. (setq-local paragraph-separate
  2655. "[ \t]*\\(//+\\|\\**\\)\\([ \t]+\\|[ \t]+<.+?>\\)$\\|^\f")
  2656. (setq-local beginning-of-defun-function 'csharp-move-back-to-beginning-of-defun)
  2657. ;; `end-of-defun-function' can remain forward-sexp !!
  2658. (set (make-local-variable 'comment-auto-fill-only-comments) t)
  2659. (set (make-local-variable 'syntax-propertize-function)
  2660. 'csharp-mode-syntax-propertize-function)
  2661. ;; required since Emacs git master
  2662. ;; https://github.com/emacs-mirror/emacs/commit/edcdf64960a2ab4e8d9ce4419874e43b6d3ccee4
  2663. ;;
  2664. ;; Basically syntax-propertize-function is a construct which belongs
  2665. ;; to font-lock. But correct indentation depends on
  2666. ;; syntax-properties of the text, and that should ideally be
  2667. ;; independent of font-lock being activated or not.
  2668. ;;
  2669. ;; For csharp-mode, this means that with font-lock disabled, we wont
  2670. ;; have our syntax-properties set correctly, and indentation will
  2671. ;; suffer.
  2672. ;;
  2673. ;; To patch our way around this, we issue a syntax-propertize call
  2674. ;; manually, font-lock enabled or not.
  2675. (with-silent-modifications
  2676. (csharp-mode-syntax-propertize-function (point-min) (point-max))))
  2677. (provide 'csharp-mode)
  2678. ;;; csharp-mode.el ends here