Emacs Dmacros

Has anyone written a set of dmacros for use with emacs? If so, are you willing to share?

TIA!

Emily

Not yet, not dmacro, but aiming at Yasnippets[1] especially for $this->assert* in unit test functions.

In addition, I hacked together these two functions below:




(defun dmj/php-mode/guess-current-function ()

  "Return name of current function."

  (interactive)

  (let (func)

    (save-excursion

      (while (and (null func)

		  (re-search-backward "{[^}]*" nil t))

	(if (looking-back

	     "function[ \t\r\n]+\\([[:alnum:]_]+\\)[ \t\r\n]*([^)]*)[ \t\r\n]*")

	    (setq func (match-string-no-properties 1)))))

    (unless func

      (let ((line (thing-at-point 'line)))

	(if (string-match "\\($[[:alnum:]_]+\\)" line)

	    (setq func (match-string-no-properties 1 line)))))

    func))



Useful for ChangeLog entries via C-x 4 a and to jump to corresponding unit test.

Second function requires eproject.el for lightweight project management and jumps to corresponding unit test method depending on buffer and point (i.e. method point is in). Stubs out test class and test function if necessary.




(defun yii/phpunit-jump-to-file ()

  "*Open test file for current file."

  (interactive)

  (let* ((root (eproject-root))

	 (bfn (buffer-file-name))

	 (func-maybe (dmj/php-mode/guess-current-function))

	 (tfunc (and (stringp func-maybe)

		     (not (= (elt func-maybe 0) ?\$))

		     (format "test%s%s"

		      (upcase (substring func-maybe 0 1))

		      (substring func-maybe 1))))

	 (class (file-name-sans-extension (file-name-nondirectory bfn)))

	 (tfile (format "%s/protected/tests/unit/%sTest.php"

			root

			class))

	 (visiting (find-buffer-visiting tfile)))

    (when root

      (switch-to-buffer-other-window (or visiting

					 (find-file-noselect tfile)))

      (goto-char (point-min))

      (unless (re-search-forward

	       (format "class[ \t\r\n]+%sTest[ \r\n\t]+extends" class) nil t)

	(insert (format "<?php


/**

 * Unit test for %s class

 */


class %sTest extends CDbTestCase {


  public $fixtures = array('%s' => '%s');


}" class class (concat (downcase class) "s") class)))

      (goto-char (point-min))

      (unless (or (null tfunc)

		  (re-search-forward (format "public function %s" tfunc) nil t))

	(goto-char (point-max))

	(search-backward "}" nil t)

	(insert (format "

public function %s () {

  

}


" tfunc))

	(end-of-line -2)))))



[1] http://code.google.com/p/yasnippet/

Thanks for sharing this, I write unit tests a lot so this will be very handy! :)

If any of you Emacs geeks has some time on your hands, it would be cool to have a Yii minor-mode. :)

Someone did one for CakePHP:

http://www.emacswiki.org/emacs-en/Cake

I am using Emacs with ECB (Cedet) and like it.

However, I am not able to figure out how to teach it about Yii.

How do you guys set it all up? :)

I’m not an elisp geek, so I can’t write a minor mode.

I’m using PHP-mode, with a bunch of dmacros I’ve added. But I’d love a minor mode too!

Post here if you write one or find one, thanks!

:-*

Sorry for the late reply, I though I had enable notification for this thread but obviously I didn’t.

Well, good opportunity to improve your elisp-skills, eh ;)

Before designing a Yii specific minor mode the most important questions is: Which problems should this mode address?

I’ve been working with Yii for appr. 4 months now and the only thing I’m eager to implement is access to Yii’s class reference from inside Emacs. Something similar to C-h f (eq M-x describe-function RET) for Emacs Lisp.

My setup

  1. IDO for completion (everywhere)

emacswiki.org/emacs/InteractivelyDoThings

IDO and flex matching makes it easy to change buffers (=C-b=) and open files.




(ido-mode 1)

(setq ido-everywhere t)

(setq ido-enable-flex-matching t)

(setq ido-enable-last-directory-history nil)



  1. eproject.el - lightweight project management

eproject servers to purposes:

2.1. Anchor the project files

I use two different computers with a different location of the project files (Windows vs. Linux). The defun (eproject-root) resolves the root of the project.

2.2. Setup project specific configuration

Currently this is just modifying the name of ChangeLog to be always at the root at the project. I use Emacs’ function `add-change-log-entry-other-window’ (=C-x 4 a=) to record changes in methods, classes, and attributes before creating the commit log entry for Git.

2.3. Config




;; Use IDO for completing.

(setq eproject-completing-read-function #'eproject--ido-completing-read)


(add-hook 'generic-git-project-file-visit-hook 'dmaus/eproject/initialize-generic-git-project)

(defun dmaus/eproject/initialize-generic-git-project ()

  "*Initialize generic git project."

  (let ((tags-file (concat (eproject-root) "TAGS")))

    (when (file-exists-p tags-file)

      (make-local-variable 'tags-file-name)

      (setq tags-file-name tags-file))))


;; Current work project: Web application using Yii Application Framework

(define-project-type php/yii (generic-git) (look-for "framework/yiic"))

(add-hook 'php/yii-project-file-visit-hook 'dmaus/yii/initialize-project)


(defun dmaus/yii/initialize-project ()

  "*Initialzie settings for Yii based project."

  (dmaus/eproject/initialize-generic-git-project)

  (unless (boundp 'change-log-default-name) (setq change-log-default-name nil))

  (make-local-variable 'change-log-default-name)

  (setq change-log-default-name

	(format "%sChangeLog" (eproject-root))))


(global-set-key (kbd "M-C-j") 'dmaus/yii/phpunit-jump-to-file)

(defun dmaus/yii/phpunit-jump-to-file ()

  "*Open test file for current file."

  (interactive)

  (let* ((root (eproject-root))

         (bfn (buffer-file-name))

         (func-maybe (dmaus/php-mode/guess-current-function))

         (tfunc (and (stringp func-maybe)

                     (not (= (elt func-maybe 0) ?\$))

                     (format "test%s%s"

                      (upcase (substring func-maybe 0 1))

                      (substring func-maybe 1))))

         (class (file-name-sans-extension (file-name-nondirectory bfn)))

         (tfile (format "%s/protected/tests/unit/%sTest.php"

                        root

                        class))

         (visiting (find-buffer-visiting tfile)))

    (when root

      (switch-to-buffer-other-window (or visiting

                                         (find-file-noselect tfile)))

      (goto-char (point-min))

      (unless (re-search-forward

               (format "class[ \t\r\n]+%sTest[ \r\n\t]+extends" class) nil t)

        (insert (format "<?php


/**

 * Unit test for %s class

 */


class %sTest extends CDbTestCase {


  public $fixtures = array('%s' => '%s');


}" class class (concat (downcase class) "s") class)))

      (goto-char (point-min))

      (unless (or (null tfunc)

                  (re-search-forward (format "public function %s" tfunc) nil t))

        (goto-char (point-max))

        (search-backward "}" nil t)

        (insert (format "

public function %s () {


}


" tfunc))

        (end-of-line -2)))))



  1. PHP Mode, shipped with nXHTML mode

Customized mode initialization (indentation, enable skeleton mode, custom def to guess name of current php function).




;;; config.d/nxhtml.el --- nXHTML configuration


(load "~/.emacs.d/site-lisp.d/nxhtml/autostart")


;; Disable Emacs debugger.  For some reasone loading nxhtml enables

;; `debug-on-error' and `debug-on-quit'.

(setq debug-on-error nil)

(setq debug-on-quit nil)


;; Local copy of PHP Manual

(setq php-manual-path "~/.emacs.d/docs/html/php-chunked/xhtml/")


;; Unregister PHP files to be loaded in mumamo-mode.  In most cases I

;; edit plain PHP files.

(mapc (lambda (pattern)

	(if (string-match "\\.php" (car pattern))

	    (setcdr pattern 'php-mode))) auto-mode-alist)


;; Customized php-mode initialization

(add-hook 'php-mode-hook 'dmaus/php-mode/initialize)

(defun dmaus/php-mode/initialize ()

  "*Custom php-mode initializion.

Set up coding style and mode-specific keybindings."

  (setq indent-tabs-mode nil)

  (setq fill-column 80)

  (setq c-basic-offset 2)

  (c-set-offset 'arglist-cont 0)

  (c-set-offset 'arglist-intro '+)

  (c-set-offset 'case-label 2)

  (c-set-offset 'arglist-close 0)

  (make-variable-buffer-local 'add-log-current-defun-function)

  (setq add-log-current-defun-function 'dmaus/php-mode/guess-current-function)

  (make-variable-frame-local 'skeleton-pair)

  (setq skeleton-pair t)

  (define-key php-mode-map (kbd "RET") 'newline-and-indent)

  (define-key php-mode-map (kbd "{") 'skeleton-pair-insert-maybe)

  (define-key php-mode-map (kbd "(") 'skeleton-pair-insert-maybe)

  (define-key php-mode-map (kbd "[") 'skeleton-pair-insert-maybe)

  (define-key php-mode-map (kbd "\"") 'skeleton-pair-insert-maybe)

  (define-key php-mode-map (kbd "'") 'skeleton-pair-insert-maybe)

  (define-key php-mode-map (kbd "C-<tab>") 'php-complete-function))


;; Guess name of current function.  Used for ChangeLog entries and

;; moving between classes and their unit tests classes.

(defun dmaus/php-mode/guess-current-function ()

  "Return name of current function."

  (interactive)

  (let (func)

    (save-excursion

      (while (and (null func)

                  (re-search-backward "{[^}]*" nil t))

        (if (looking-back

             "function[ \t\r\n]+\\([[:alnum:]_]+\\)[ \t\r\n]*([^)]*)[ \t\r\n]*")

            (setq func (match-string-no-properties 1)))))

    (unless func

      (let ((line (thing-at-point 'line)))

        (if (string-match "\\($[[:alnum:]_]+\\)" line)

            (setq func (match-string-no-properties 1 line)))))

    func))



  1. Auto-complete

cx4a.org/software/auto-complete/

Extremly useful. Offers completion based of content of opened files, works really nice to complete long and very long variable or function names.

  1. Whitespaces

Cleanup whitespaces before saving .php files + toggle white-space-mode by pressing C-c C-x w




;; Cleanup whitespace in some modes

(defvar dmaus/cleanup-whitespace-mode-list nil

  "List of modes for which whitespace should be cleaned up.

Used by `dmaus/cleanup-whitespace-maybe'.")

(setq dmaus/cleanup-whitespace-mode-list (list 'php-mode))


(defun dmaus/cleanup-whitespace-maybe ()

  "*Cleanup whitespace."

  (if (member major-mode dmaus/cleanup-whitespace-mode-list)

      (whitespace-cleanup)))

(add-hook 'before-save-hook 'dmaus/cleanup-whitespace-maybe)






(global-set-key (kbd "C-c C-x w") 'whitespace-mode)



(global-set-key might collide with other major modes)

  1. PHP REPL

Original version: github.com/ieure/php_repl

Fixed Emacs integration: github.com/dmj/php_repl

Installed via PEAR, offers a Read Eval Print Loop (interactive shell) for PHP. Provides Emacs integration (broken, fixed in the fixed version, 2nd link).

M-x run-php RET

  1. Excuberant Tags

A TAGS file inside (eproject-root) constains references to all PHP classes, methods and variables and allows fast jumping to the definition via =M-.= – tags file location is setup in the eproject initialization hook.

And that’s pretty it.

Best,

– David

David,

Wow! Thanks so much for the wonderful functions; I’ll try them.

An invaluable tool for me in emacs is dmacros. You’re no doubt aware of these, but for others tuning in, dmacros are a handy way to insert code snippets. E.g., a dmacro called “log”:




log	indent	interactive set stmt

Yii::log("@");

mark



I can insert that with a call to insert-dmacro, then I enter "log" at the prompt.

So, I’m still looking for a robust set of Yii-specific dmacros. My set is just a ragtag bunch. Would love all kinds of dmacros for querying the db, for example.

Em

:mellow: