From 2ddaa5a5bf4d74b51f64720ea1be94bf06394c41 Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Sat, 7 May 2016 15:00:54 -0400 Subject: Define defun navigation commands --- NEWS | 3 ++ snakemake-mode.el | 54 ++++++++++++++++++++++++++++ snakemake-test.el | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+) diff --git a/NEWS b/NEWS index 3bef2db..1f73c4f 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,9 @@ NEWS -- history of user-visible changes -*- mode: org; -*- - ".rules" has been added as a suffix for Snakemake files. +- ~beginning-of-defun~ and ~end-of-defun~ implementations for rule + blocks are now defined. + * v0.4.0 ** New features diff --git a/snakemake-mode.el b/snakemake-mode.el index 853f356..a598aca 100644 --- a/snakemake-mode.el +++ b/snakemake-mode.el @@ -158,6 +158,54 @@ (when (<= rule-start pos rule-end) (cons rule-start rule-end)))))))) +(defun snakemake-beginning-of-block (&optional arg) + "Move to beginning of rule block. +With ARG, do it that many times. Negative ARG signals to move +forward rather than backward." + (when (or (null arg) (= arg 0)) + (setq arg 1)) + (funcall (if (> arg 0) + #'re-search-backward + (lambda (&rest args) + (end-of-line) + (prog1 (apply #'re-search-forward args) + (beginning-of-line)))) + snakemake-rule-or-subworkflow-re + nil 'move (abs arg)) + (looking-at-p snakemake-rule-or-subworkflow-re)) + +(defun snakemake-end-of-block () + "Move to end of rule or subworkflow block." + (let ((bounds (snakemake-block-bounds))) + (when bounds + (goto-char (cdr bounds))))) + +(defun snakemake-beginning-of-defun (&optional arg) + "Move to beginning of current rule block or function. +With ARG, do it that many times. Negative ARG signals to move +forward rather than backward." + (when (or (null arg) (= arg 0)) + (setq arg 1)) + (let ((choose-fn (if (> arg 0) #'max #'min)) + (cands (delq nil + (mapcar + (lambda (f) + (save-excursion (and (funcall f arg) (point)))) + (list #'snakemake-beginning-of-block + #'python-nav-beginning-of-defun))))) + (cond (cands + (goto-char (apply choose-fn cands))) + ((> arg 0) + (goto-char (point-min)) + nil) + (t + (goto-char (point-max)) + nil)))) + +(defun snakemake-end-of-defun () + "Move to end of current rule block or function." + (or (snakemake-end-of-block) + (python-nav-end-of-defun))) ;;; Indentation @@ -347,6 +395,12 @@ embedded R, you need to set mmm-global-mode to a non-nil value such as 'maybe.") #'snakemake-imenu-create-index) (set (make-local-variable 'indent-line-function) 'snakemake-indent-line-function) (set (make-local-variable 'indent-region-function) nil) + + (set (make-local-variable 'beginning-of-defun-function) + #'snakemake-beginning-of-defun) + (set (make-local-variable 'end-of-defun-function) + #'snakemake-end-of-defun) + (set (make-local-variable 'font-lock-defaults) `(,(append snakemake-font-lock-keywords python-font-lock-keywords)))) diff --git a/snakemake-test.el b/snakemake-test.el index d6f3d81..d725345 100644 --- a/snakemake-test.el +++ b/snakemake-test.el @@ -575,6 +575,112 @@ rule abc: output: 'file'" (snakemake-block-bounds)))) +(ert-deftest snakemake-test-beginning-of-block () + (should + (string= " +rule abc: + output: 'file'" + (snakemake-with-temp-text + " +rule abc: + output: 'file'" + (snakemake-beginning-of-block) + (buffer-substring (point) (point-max))))) + (should + (string= "rule abc: + output: 'file'" + (snakemake-with-temp-text + " +rule abc: + output: 'file'" + (snakemake-beginning-of-block) + (buffer-substring (point) (point-max))))) + (should + (string= "rule abc: + output: 'file' + +" + (snakemake-with-temp-text + " +rule abc: + output: 'file' + +" + (snakemake-beginning-of-block) + (buffer-substring (point) (point-max))))) + (should + (string= "rule abc: + \"\"\"docstring header + + docstring line + \"\"\" + output: 'file'" + (snakemake-with-temp-text + " +rule abc: + \"\"\"docstring header + + docstring line + \"\"\" + output: 'file'" + (snakemake-beginning-of-block) + (buffer-substring (point) (point-max))))) + (should + (string= "subworkflow otherworkflow: + workdir: '../path/to/otherworkflow' + snakefile: '../path/to/otherworkflow/Snakefile'" + (snakemake-with-temp-text + " +subworkflow otherworkflow: + workdir: '../path/to/otherworkflow' + snakefile: '../path/to/otherworkflow/Snakefile'" + (snakemake-beginning-of-block) + (buffer-substring (point) (point-max)))))) + +(ert-deftest snakemake-test-end-of-block () + (should + (string= " +rule abc: + output: 'file' + + +" + (snakemake-with-temp-text + " +rule abc: + output: 'file' + + +" + (snakemake-end-of-block) + (buffer-substring (point-min) (point))))) + (should + (string= " +rule abc: + output: 'file' +" + (snakemake-with-temp-text + " +rule abc: + output: 'file' + +rule xyz: + input: 'file'" + (snakemake-end-of-block) + (buffer-substring (point-min) (point))))) + (should + (string= " +rule abc: + output: 'file'" + (snakemake-with-temp-text + " +rule abc: + output: 'file' +rule xyz: + input: 'file'" + (snakemake-end-of-block) + (buffer-substring (point-min) (point)))))) + ;;; snakemake.el -- cgit v1.2.3