Difference between revisions of "Emacs"

From Apertium
Jump to navigation Jump to search
(move point to after word in <r> elt)
m (sort&goto-pardef)
Line 4: Line 4:
 
I often define keyboard macros as I edit, some of these I record as
 
I often define keyboard macros as I edit, some of these I record as
 
functions which you can put in your .emacs, since they come in handy
 
functions which you can put in your .emacs, since they come in handy
time and again, eg. this one for bidix:
+
time and again. I use
  +
[[Format dictionaries|Apertium-dixtools]]-formatted dix, some of the functions below won't work with the regular format (at least <code>sort-pardef</code>). The code below adds keyboard shortcuts <code>C-c L</code> and <code>C-c R</code> which make LR or RL restricted copies of &lt;e&gt;'s, <code>C-c G</code> which finds the pardef of a dictionary entry (and lets you go back with <code>C-u C-SPC</code>) and <code>C-c S</code> which sorts a pardef by its right-hand-side &lt;r&gt;.
   
 
<pre>
 
<pre>
(defun nxml-dix-up-to-e ()
+
(defun nxml-dix-up-to (eltname)
"Move point before the <e> element we're looking at."
+
"Move point before the element `eltname' (a string, eg. \"e\")
  +
which we're looking at."
(interactive)
 
 
(nxml-token-after)
 
(nxml-token-after)
 
(goto-char xmltok-start)
 
(goto-char xmltok-start)
 
(let ((tok (xmltok-start-tag-qname)))
 
(let ((tok (xmltok-start-tag-qname)))
(while (not (or (equal tok "e") (equal tok "<e")))
+
(while (not (or (equal tok eltname) (equal tok (concat "<" eltname))))
 
(nxml-backward-up-element)
 
(nxml-backward-up-element)
 
(nxml-token-after)
 
(nxml-token-after)
Line 23: Line 24:
 
restriction."
 
restriction."
 
(interactive "P")
 
(interactive "P")
(nxml-dix-up-to-e)
+
(nxml-dix-up-to "e")
 
(kill-sexp) (yank) (newline-and-indent) (yank)
 
(kill-sexp) (yank) (newline-and-indent) (yank)
 
(goto-char (mark t))
 
(goto-char (mark t))
Line 33: Line 34:
 
(nxml-backward-up-element) (nxml-forward-element) (forward-word 2)))
 
(nxml-backward-up-element) (nxml-forward-element) (forward-word 2)))
   
  +
(defun nxml-dix-goto-pardef ()
;; whatever keys you prefer:
 
  +
"Call from an entry to go to its pardef. Mark is pushed so you
(define-key nxml-mode-map (kbd "C-c L") 'nxml-dix-restriction-copy)
 
  +
can go back with C-u \\[set-mark-command]."
(define-key nxml-mode-map (kbd "C-c R")
 
(lambda nil (interactive)
+
(interactive)
  +
(if (save-excursion
"Make a copy of the Apertium element we're looking at, and
 
  +
(nxml-dix-up-to "e")
  +
(re-search-forward "n=\"\\([^\"]*\\)\"")
  +
(let ((pdname (match-string 1)))
  +
(goto-char (point-min))
  +
(if (re-search-forward
  +
(concat "<pardef *n=\"" pdname "\"") nil t)
  +
(setq pos (match-beginning 0)))))
  +
(progn (push-mark)
  +
(goto-char pos))))
  +
  +
(defun nxml-dix-sort-e-by-r (reverse beg end)
  +
"Sort region alphabetically by contents of <r> element;
  +
argument means descending order. Assumes <e> elements never
  +
occupy more than one line.
  +
  +
Called from a program, there
  +
are three arguments: REVERSE (non-nil means reverse order), BEG
  +
and END (region to sort). The variable `sort-fold-case'
  +
determines whether alphabetic case affects the sort order."
  +
(interactive "P\nr")
  +
(save-excursion
  +
(save-restriction
  +
(narrow-to-region beg end)
  +
(goto-char (point-min))
  +
(let ;; To make `end-of-line' and etc. to ignore fields.
  +
((inhibit-field-text-motion t))
  +
(sort-subr reverse
  +
;; todo: use nxml-dix-up-to and
  +
;; nxml-forward-element to make it XML general
  +
'forward-line
  +
'end-of-line
  +
(lambda ()
  +
(nxml-forward-element)
  +
(nxml-backward-down-element 2)
  +
(nxml-backward-element)))))))
  +
  +
(defun nxml-dix-sort-pardef (reverse)
  +
"Sort a pardef using `nxml-dix-sort-e-by-r'. Requires pardef to
  +
be formatted as per apertium-dixtools."
 
(interactive "P")
  +
(save-excursion
  +
(nxml-dix-up-to "pardef")
  +
(mark-sexp)
  +
(forward-line)
  +
(exchange-point-and-mark)
  +
(beginning-of-line)
  +
(nxml-dix-sort-e-by-r reverse (mark) (point))))
  +
  +
;; add keyboard shortcuts on loading nxml-mode:
  +
(add-hook 'nxml-mode-hook
  +
(lambda ()
 
(define-key nxml-mode-map (kbd "C-c L") 'nxml-dix-restriction-copy)
 
(define-key nxml-mode-map (kbd "C-c R")
  +
(lambda nil (interactive)
 
"Make a copy of the Apertium element we're looking at, and
 
add an RL restriction to the copy."
 
add an RL restriction to the copy."
(nxml-dix-restriction-copy 'RL)))
+
(nxml-dix-restriction-copy 'RL)))
  +
(define-key nxml-mode-map (kbd "C-c S") 'nxml-dix-sort-pardef)
  +
(define-key nxml-mode-map (kbd "C-c G") 'nxml-dix-goto-pardef)))
 
</pre>
 
</pre>
   

Revision as of 08:16, 22 June 2009

Emacs has a nice xml editing mode called nXML.

I often define keyboard macros as I edit, some of these I record as functions which you can put in your .emacs, since they come in handy time and again. I use Apertium-dixtools-formatted dix, some of the functions below won't work with the regular format (at least sort-pardef). The code below adds keyboard shortcuts C-c L and C-c R which make LR or RL restricted copies of <e>'s, C-c G which finds the pardef of a dictionary entry (and lets you go back with C-u C-SPC) and C-c S which sorts a pardef by its right-hand-side <r>.

(defun nxml-dix-up-to (eltname)
  "Move point before the element `eltname' (a string, eg. \"e\")
which we're looking at."
  (nxml-token-after)
  (goto-char xmltok-start)
  (let ((tok (xmltok-start-tag-qname)))
    (while (not (or (equal tok eltname) (equal tok (concat "<" eltname))))
      (nxml-backward-up-element)
      (nxml-token-after)
      (setq tok (xmltok-start-tag-qname)))))

(defun nxml-dix-restriction-copy (&optional RL)
  "Make a copy of the Apertium element we're looking at, and add
an LR restriction to the copy. A prefix argument makes it an RL
restriction."
  (interactive "P")
  (nxml-dix-up-to "e")
  (kill-sexp) (yank) (newline-and-indent) (yank)
  (goto-char (mark t))
  (let ((dir (if RL "RL" "LR")))
    (forward-word) (insert (concat " r=\"" dir "\"")))
  (forward-char) (just-one-space) (delete-backward-char 1)
  (forward-word 3)
  (when RL
    (nxml-backward-up-element) (nxml-forward-element) (forward-word 2)))

(defun nxml-dix-goto-pardef ()
  "Call from an entry to go to its pardef. Mark is pushed so you
can go back with C-u \\[set-mark-command]."
  (interactive)
  (if (save-excursion
	(nxml-dix-up-to "e")
	(re-search-forward "n=\"\\([^\"]*\\)\"")
	(let ((pdname (match-string 1)))
	  (goto-char (point-min))
	  (if (re-search-forward
	       (concat "<pardef *n=\"" pdname "\"") nil t)
	      (setq pos (match-beginning 0)))))
      (progn (push-mark)
	     (goto-char pos))))

(defun nxml-dix-sort-e-by-r (reverse beg end)
  "Sort region alphabetically by contents of <r> element;
argument means descending order. Assumes <e> elements never
occupy more than one line.

Called from a program, there
are three arguments: REVERSE (non-nil means reverse order), BEG
and END (region to sort).  The variable `sort-fold-case'
determines whether alphabetic case affects the sort order."
  (interactive "P\nr")
  (save-excursion
    (save-restriction
      (narrow-to-region beg end)
      (goto-char (point-min))
      (let ;; To make `end-of-line' and etc. to ignore fields.
	  ((inhibit-field-text-motion t))
	(sort-subr reverse
		   ;; todo: use nxml-dix-up-to and
		   ;; nxml-forward-element to make it XML general
		   'forward-line
		   'end-of-line
		   (lambda ()
		     (nxml-forward-element)
		     (nxml-backward-down-element 2)
		     (nxml-backward-element)))))))

(defun nxml-dix-sort-pardef (reverse)
  "Sort a pardef using `nxml-dix-sort-e-by-r'. Requires pardef to
be formatted as per apertium-dixtools."
  (interactive "P")
  (save-excursion
    (nxml-dix-up-to "pardef")
    (mark-sexp)
    (forward-line)
    (exchange-point-and-mark)
    (beginning-of-line)
    (nxml-dix-sort-e-by-r reverse (mark) (point))))

;; add keyboard shortcuts on loading nxml-mode:
(add-hook 'nxml-mode-hook	
	  (lambda ()
	    (define-key nxml-mode-map (kbd "C-c L") 'nxml-dix-restriction-copy)
	    (define-key nxml-mode-map (kbd "C-c R")
	      (lambda nil (interactive)
		"Make a copy of the Apertium element we're looking at, and
add an RL restriction to the copy."
		(nxml-dix-restriction-copy 'RL)))
	    (define-key nxml-mode-map (kbd "C-c S") 'nxml-dix-sort-pardef)
	    (define-key nxml-mode-map (kbd "C-c G") 'nxml-dix-goto-pardef)))

Also, if you like having all <i> elements aligned at eg. column 25, the following in your .emacs lets you do M-x align on a region to achieve that, and also aligns <p> to 10 and <r> to 44 (for bidix):

 (add-hook 'align-load-hook
	  (lambda ()
	    (add-to-list 'align-rules-list
			 '(nxml-dix-i-align
			   (regexp . "\\(\\s-*\\)\\(<i.*\\)$")
			   (modes . '(nxml-mode))
			   (column . 25)))
	    (add-to-list 'align-rules-list
			 '(nxml-dix-r-align
			   (regexp . "\\(\\s-*\\)\\(<r>.*\\)$")
			   (tab-stop . nil)
			   (modes . '(nxml-mode))
			   (column . 44)))
	    (add-to-list 'align-rules-list
			 '(nxml-dix-p-align
			   (regexp . "\\(\\s-*\\)\\(<p>.*\\)$")
			   (modes . '(nxml-mode))
			   (column . 10)))))

See also

Emacs C style for Apertium hacking