用Emacs编写mybatis

Posted 西西弗斯的痛苦与无聊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用Emacs编写mybatis相关的知识,希望对你有一定的参考价值。

用Emacs编写mybatis

用Emacs编写mybatis

Table of Contents

1 效果图

screenshot_2017-12-16_22-01-27.png

2 配置

现在web开发,最流行的orm框架非mybatis莫属了,它功能强大,编写简单灵活,可以直接编写SQL,也可以添加条件控制。但是,正是因为mybatis采用xml作为结构语言,所以,难免会有大量的xml和sql混杂在一起的代码,对这些代码对语法高亮以及自动缩减就是一个问题。
在Emacs中对xml有web-mode对其提供了非常好的支持,无论是缩进、跳转、剪切、拷贝、折叠等等操作都非常简单高效,远超各种IDE。对SQL也有很好的支持。但是对于mybatis却没有任何支持,用web-mode则sql无法高亮和缩进,用sql则基础xml结构缩减有问题。网上关于Emacs中编写mybatis的也甚少有涉及的,说明用Emacs来进行java开发的还是很少的。于是,只能本人自己思考解决方案了。
我记得之前Purcell大神写了一个mmm-mode,说是可以把多个mode放到一起,不知是作何用,说不定可以让web-mode支持sql语句。于是就在package管理中安装了mmm-mode。然后,配置了web-mode中对sql-mode的支持:

(mmm-add-classes
 \'((web-sql-select :submode sql-mode
                   :front "<select[^>]*>[ \\t]*\\n" :back "[ \\t]*</select>")
   (web-sql-insert :submode sql-mode
                   :front "<insert[^>]*>[ \\t]*\\n" :back "[ \\t]*</insert>")
   (web-sql-update :submode sql-mode
                   :front "<update[^>]*>[ \\t]*\\n" :back "[ \\t]*</update>")
   (web-sql-delete :submode sql-mode
                   :front "<delete[^>]*>[ \\t]*\\n" :back "[ \\t]*</delete>")
   ))

(mmm-add-mode-ext-class \'web-mode nil \'web-sql-select)
(mmm-add-mode-ext-class \'web-mode nil \'web-sql-insert)
(mmm-add-mode-ext-class \'web-mode nil \'web-sql-update)
(mmm-add-mode-ext-class \'web-mode nil \'web-sql-delete)

其实就是根据正则表达式来确定哪些代码是属于指定的submode的,对于mybatis中的sql语句而言,很简单就可以找出哪些是sql语句了。

然后,比较难的是对齐,因为两种语言混杂在一起,用其中任一一种都有问题。经过仔细的思考和试验之后,发现一种配置是相对合理,且实现简单的:

(defun mmm-indent-line-web-sql-submode ()
  (web-mode-propertize)
  (let (cur-type prev-type)
    (save-excursion
      (back-to-indentation)
      (setq cur-type (get-text-property (point) \'tag-type)))
    (save-excursion
      (previous-line)
      (back-to-indentation)
      (setq prev-type (get-text-property (point) \'tag-type)))
    (if (or
         (not (or prev-type cur-type))                   ; both lines sql
         (and (not prev-type) (eq cur-type \'start)) ; sql -> xml
         )
        (sql-indent-line)
      (web-mode-indent-line))))

(defun mmm-indent-line-web-sql ()
  (interactive)
  (funcall
   (save-excursion
     (back-to-indentation)
     (mmm-update-submode-region)
     (if (and mmm-current-overlay
              (> (overlay-end mmm-current-overlay) (point)))
         \'mmm-indent-line-web-sql-submode
       \'web-mode-indent-line))))

(setq mmm-indent-line-function \'mmm-indent-line-web-sql)

如此,只使用mmm-mode用来支持mybatis的话,再加上一些其他的小配置,比如更新之后自动刷新语法高亮等,就很简单了:

(setq mmm-parse-when-idle t)
(setq mmm-global-classes nil)
(setq mmm-classes-alist nil)
(setq mmm-mode-ext-classes-alist nil)

总的配置,可以去我的github上查看,也可以直接拷贝下面的代码:

;;; init-mmm.el --- Summary
;;; Commentary:
;; comments

;;; Code:
(use-package mmm-mode
  ;; :hook ((web-mode . mmm-mode))
  :commands mmm-mode
  :config
  (defun mmm-indent-line-web-sql-submode ()
    (web-mode-propertize)
    (let (cur-type prev-type)
      (save-excursion
        (back-to-indentation)
        (setq cur-type (get-text-property (point) \'tag-type)))
      (save-excursion
        (previous-line)
        (back-to-indentation)
        (setq prev-type (get-text-property (point) \'tag-type)))
      (if (or
           (not (or prev-type cur-type))                   ; both lines sql
           (and (not prev-type) (eq cur-type \'start)) ; sql -> xml
           )
          (sql-indent-line)
        (web-mode-indent-line))))

  (defun mmm-indent-line-web-sql ()
    (interactive)
    (funcall
     (save-excursion
       (back-to-indentation)
       (mmm-update-submode-region)
       (if (and mmm-current-overlay
                (> (overlay-end mmm-current-overlay) (point)))
           \'mmm-indent-line-web-sql-submode
         \'web-mode-indent-line))))

  (setq mmm-parse-when-idle t)
  (setq mmm-global-classes nil)
  (setq mmm-classes-alist nil)
  (setq mmm-mode-ext-classes-alist nil)
  (setq mmm-indent-line-function \'mmm-indent-line-web-sql)

  (mmm-add-classes
   \'((web-sql-select :submode sql-mode
                     :front "<select[^>]*>[ \\t]*\\n" :back "[ \\t]*</select>")
     (web-sql-insert :submode sql-mode
                     :front "<insert[^>]*>[ \\t]*\\n" :back "[ \\t]*</insert>")
     (web-sql-update :submode sql-mode
                     :front "<update[^>]*>[ \\t]*\\n" :back "[ \\t]*</update>")
     (web-sql-delete :submode sql-mode
                     :front "<delete[^>]*>[ \\t]*\\n" :back "[ \\t]*</delete>")
     ))

  (mmm-add-mode-ext-class \'web-mode nil \'web-sql-select)
  (mmm-add-mode-ext-class \'web-mode nil \'web-sql-insert)
  (mmm-add-mode-ext-class \'web-mode nil \'web-sql-update)
  (mmm-add-mode-ext-class \'web-mode nil \'web-sql-delete)
  )

(provide \'init-mmm)
;;; init-mmm.el ends here

Date: 2017-12-16 21:17

Author: WEN YANG

Created: 2017-12-16 Sat 22:02

Emacs 25.3.1 (Org mode 8.2.10)

Validate

以上是关于用Emacs编写mybatis的主要内容,如果未能解决你的问题,请参考以下文章

Emacs

如何为新语言编写 emacs 模式?

mybatis动态sql之利用sql标签抽取可重用的sql片段

CEO 的 Emacs 秘籍

PHP必用代码片段

MyBatis查询mysql数据返回null