summaryrefslogblamecommitdiffstats
path: root/emacs.d/lisp/delphi-mode-ench.el
blob: 2427362c6adb928c2f5c5930a2178c3a43c01cfc (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                  

             




                                                                                                                                            























































                                                                            
                                                     





































































































































































                                                                                                         
;;; delphi-mode-ench.el
(require 'compile)
(require 'cl)

(pushnew '("^\\([-a-zA-Z0-9\\.\\/_~]+\\)(\\([0-9]+\\),\\([0-9]+\\))\s\\([Ff]atal:\\|[Nn]ote:\\|[Ww]arning:\\|[Ee]rror:\\)\s\\(.*$\\)" 1 2 3)
	 compilation-error-regexp-alist)

(setq auto-mode-alist (cons '("\\.pas" . delphi-mode) auto-mode-alist))

(setq delphi-unit-sections
      '(implementation program library package))

(defconst delphi-method-types-regexp
  "\\(procedure\\|function\\|constructor\\|destructor\\)"
  "Regular expression for delphi method types")

(defconst delphi-method-signature-regexp
  ;; like mymethod(myvar1:varType; myvar2:varType=defaultvalue):TReturnType
  (concat
   "\\("
   (concat
    ;; mymethod
    "[_a-zA-Z][_a-zA-Z0-9]*"

    ;; (myvar1:varType; myvar2:varType=defaultvalue)
    "\\((.*)\\)?"

    ;; : TReturnType
    "\\( *: *[_a-zA-Z][_a-zA-Z0-9]*\\)?")
   "\\)")
  "Signature of a delphi method")

(defconst delphi-class-declaration-regexp
  ;;like TMyClass = class(TParentClass)
  "\\(?:^\\|[ \t]\\)[ \t]*\\([_a-zA-Z][_a-zA-Z0-9]*\\) *= *class"
  "Class declaration regexp")

(defvar imenu--function-name-regexp-delphi
  (concat
   "^[ \t]*\\(function\\|procedure\\|constructor\\|destructor\\)[ \t]+"
   "\\([_a-zA-Z][_a-zA-Z0-9]*\\.\\)?"
   "\\([_a-zA-Z][_a-zA-Z0-9]*\\)")
  "Re to get function/procedure names in Delphi.")

(defun delphi-get-classes ()
  (save-excursion
    (goto-char (point-min))

    (let ((classes '()))
      (while (re-search-forward delphi-class-declaration-regexp nil t)
	(push (match-string-no-properties 1) classes))
      classes)))

(defun delphi-in-string (&optional pos)
  (delphi-is (delphi-token-kind (delphi-token-at (point))) delphi-strings))

(defun delphi-in-comment (&optional pos)
  (delphi-is (delphi-token-kind (delphi-token-at (point))) delphi-comments))

(defun delphi-is-definition (&optional pos)
  (let ((class (save-excursion (delphi-in-class-definition))))
  (if class class
    (if pos (goto-char pos))
    (re-search-forward "\\(begin\\|implementation\\)" nil t)
    (let ((match (match-string-no-properties 1)))
      (if (equal match "implementation") 't 'nil)))))

(defun delphi-in-class-definition (&optional pos)
  (if pos (goto-char pos))

  (let ((break 't) (class nil) (open-blocks 0) (max-negative 0))
    (while (and break
		(re-search-backward (concat "\\(?:\\(?:^\\|[^_a-zA-Z0-9]\\)"
					    "\\(end\\|record\\|case\\|begin\\)"
					    "\\(?:$\\|[^_a-zA-Z0-9]\\)"
					    "\\|\\(?:^\\|[ \t]\\)"
					    "\\([_a-zA-Z][_a-zA-Z0-9]*\\)"
					    "[ \t]*=[ \t]*class\\)") nil t))

      (let ((result (match-string-no-properties 1)))
	(if (not (or (delphi-in-string) (delphi-in-comment)))
	    (cond ((equal result "end")
		   (setq open-blocks (+ open-blocks 1)))
		  ((or
		    (or
		     (equal result "record")
		     (equal result "case")) (equal result "begin"))
		   (setq open-blocks (- open-blocks 1))
		   (setq max-negative (min open-blocks max-negative)))

		  ('t  (setq break nil)
		       (if (= open-blocks max-negative)
			   (setq class (match-string-no-properties 2))))))))
    class)
)

(defun imenu--create-delphi-index (&optional regexp)
  (let ((index-alist '())
	(progress-prev-pos 0)
	(case-fold-search t))
    (goto-char (point-min))
    (imenu-progress-message progress-prev-pos 0)
    (save-match-data
      (while (re-search-forward
	      (or regexp imenu--function-name-regexp-delphi)
	      'nil 't)
	(imenu-progress-message progress-prev-pos)
	(let ((pos (save-excursion
		     (beginning-of-line)
		     (if imenu-use-markers (point-marker) (point))))
	      (function-name (match-string-no-properties 3))
	      (class-name (match-string-no-properties 2)))
	  (let ((class-def (save-excursion (delphi-is-definition pos))))
	    (let ((class-name (if class-name (substring class-name 0 -1) class-def))
		  (content (let ((sub-alist (if (not (equal class-def 't))
						 (assoc class-def index-alist)
						 index-alist)))
			     (if (not (equal class-def 'nil))
				 (cond ((assoc "Definition" sub-alist)
					(let ((alist (reverse (assoc "Definition" sub-alist))))
					  (setcdr (assoc "Definition" sub-alist)
						  (cdr (reverse (push (cons function-name pos) alist)))))
					nil)
				       (t
					(list "Definition" (cons function-name pos))))
			     	(cons function-name pos)))))

	      (if content (cond
			   ((not (or (equal class-name 'nil) (equal class-name 't)))
			    (cond ((assoc class-name index-alist)
				   (let ((alist (reverse (assoc class-name index-alist))))
				     (setcdr (assoc class-name index-alist)
					     (cdr (reverse (push content alist))))))
				  (t
				   (push (list class-name content) index-alist))
				  ))
			   (t
			    (push content index-alist))))
	      )))))
      (imenu-progress-message progress-prev-pos 100)
      (setq index-alist (nreverse index-alist))

      ; remove class-name if only one class exists
      (if (equal (length index-alist) 1) (setq index-alist (cdr (car index-alist))))
      index-alist))

(defun delphi-method-jump ()
  (cond ((save-excursion (delphi-is-definition)) (delphi-go-to-method-implementation))
	('t (delphi-go-to-method-definition))))

(defun delphi-go-to-method-definition ()
  "Move cursor to method definition of current edited method"
  (interactive)
  (re-search-backward (concat
		      delphi-method-types-regexp
		      " *"
		      "\\([_a-zA-Z][_a-zA-Z0-9]*\\)\\."
		      delphi-method-signature-regexp))
  (let
      ((class (match-string 2))
       (method (match-string 3)))
    (message "%s %s" class method)
    (re-search-backward (concat class " *= *class"))
    (re-search-forward method)))


(defun delphi-go-to-method-implementation ()
  "Move cursor to method implementation of method on current line"
  (interactive)
  (beginning-of-line)
  (let (methodtype methodname class)
    (re-search-forward (concat
			delphi-method-types-regexp
			" *"
			delphi-method-signature-regexp))
    (setq methodtype (match-string 1)
	  methodname (match-string 2))
    (re-search-backward delphi-class-declaration-regexp)
    (setq class (match-string 1))
    (re-search-forward (concat methodtype " +" class "\\." methodname))))


(defun delphi-complete-method ()
  "Create the method skeleton for method definition under cursor"
  (interactive)
  (beginning-of-line)
  (let (methodtype methodname class)
    (re-search-forward (concat
			delphi-method-types-regexp
			" *"
			delphi-method-signature-regexp))
    (setq methodtype (match-string 1)
	  methoddef (match-string 2))
    (re-search-backward delphi-class-declaration-regexp)
    (setq class (match-string 1))
    (end-of-buffer)
    (re-search-backward (concat
			 "\\("
			 delphi-method-types-regexp
			 " *"
			 class
			 "\\)\\|implementation"))
    (next-line)
    (re-search-forward (concat
			delphi-method-types-regexp
			"\\|\\(initialization\\|finalization\\|end\\.\\)"))
    (previous-line)
    (newline 2)
    (previous-line 2)
    (insert (concat methodtype " " class "." methoddef ";"))
    (newline)
    (insert "begin")
    (newline 2)
    (insert "end;")
    (previous-line)))


;;key binding
(add-hook 'delphi-mode-hook
	  '(lambda ()
	     (define-key delphi-mode-map "\C-c\C-mi" 'delphi-go-to-method-implementation)
	     (define-key delphi-mode-map "\C-c\C-md" 'delphi-go-to-method-definition)
	     (define-key delphi-mode-map "\C-c\C-mc" 'delphi-complete-method)))

; hook if starting delphi-mode
(add-hook 'delphi-mode-hook
	  '(lambda ()
	     (setq comment-start "// ")
	     (require 'imenu)
	     (setq imenu-create-index-function
		   'imenu--create-delphi-index)
	     (imenu-add-menubar-index)))