怎样维护自己hack过的package

首先感谢山人的回答,问题写好了,但是因为网络问题,没能及时上传问题的内容。现重新编辑如下:

我目前用的package都是在.emacs.d目录下的,有时候为了达到hack的目的,我会直接修改这个目录下的.el文件。 我觉得这样做的话下次如果更新package,我修改的代码可能就丢失了吧。 所以我想问问大家,平时都是怎么维护自己修改过的package的?

举个例子 我最近刚刚修改了google-translate这个package,修改的文件是~/.emacs.d/elpa/google-translate-20161206.1408/这个目录下的几个.el文件。

下面是我想到的方式,请大家指正: a. 我用的是spacemacs,刚开始我都不知道google-translate已经安装了,可能是某一个layer自带的(怎样确定package装在哪个layer中呢?)。如果我即想用自己改过的package,又想用自带该package的layer,是不是就要使用类似于如下的代码来禁止自带的package被启用(问题是任意一个layer都会提供这样的变量吗?):

(chinese :variables
               chinese-enable-youdao-dict t
               chinese-enable-fcitx t)

b. 禁用后,再使用

 (add-to-list 'load-path "path/to/mypackage")

这种方式加入自己修改过的package, path/to/mypackage就不放在.emacs.d 目录下,因为.emacs.d是clone别人的(spacemacs) 。 c. path/to/mypackage单独fork自某个package,比如上面提到的google-translate.

1 个赞

使用 github fork 一份配置,然后用 https://github.com/quelpa/quelpa 来直接从 github 安装 package

Spacemacs 的用户可以直接使用:

 (highlight-global :location (recipe :fetcher github :repo "glen-dai/highlight-global"))

这样的话,本地的文件又自动下载到了.emacs.d里面吗?还有是否存在和已有layer的配置重复问题?

Spacemace 也支持 recipe 了,这是什么都要自己搞一套么。

非 Spacemacs 用户可以试试 el-get,它内置了大量的 recipe 可直接使用:

(el-get-bundle yasnippet)
(el-get-bundle color-moccur)

或者手动指定来源,来源可以是:

  • elpa
  • 文件 url
  • 代码仓库(git/svn/hg),并可以指定 commit。如果是 github 还可以省略网址前缀
;; Locally defined recipe
(el-get-bundle yaicomplete
  :url "https://github.com/tarao/elisp.git"
  :features yaicomplete)

;; With initialization code
(el-get-bundle zenburn-theme
  :url "https://raw.githubusercontent.com/bbatsov/zenburn-emacs/master/zenburn-theme.el"
  (load-theme 'zenburn t))

(el-get-bundle tarao/tab-group-el)
;; equivalent to
;; (el-get-bundle tab-group-el :type github :pkgname "tarao/tab-group-el")

(el-get-bundle gist:4468816:pit
;; equivalent to
;; (el-get-bundle pit :type git :url "http://gist.github.com/4468816.git")

(el-get-bundle elpa:undo-tree)
;; equivalent to
;; (el-get-bundle undo-tree :type elpa)

如果已有 layer 是 spacemacs 的,你也可以 fork 一份 spacemacs,然后修改那个 layer 的 recipe,令它指向你修改后的包。我现在用的 spacemacs 就是自己稍作修改的版本。

我用过recipe,是不是这样的:

    (package-name :location (recipe
                           :fetcher github
                           :repo "github-name/package-name"))

这样就要求package必须要上传到github了,我觉得应该是先在本地修改,改好了还要测试,测试通过才会push到github。 对于测试阶段,这种方法就不合适了吧?


擦,跟山人写的是一样的:sweat: @guanghui.qu

我看这还是文档里推荐的写法 http://spacemacs.org/doc/LAYERS.html#packagesel @twlz0ne

如果已有 layer 是 spacemacs 的,你也可以 fork 一份 spacemacs,然后修改那个 layer 的 recipe,令它指向你修改后的包。我现在用的 spacemacs 就是自己稍作修改的版本。

如果想本地测试可以用 :location local,写完整就是:

(package-name :location local)

然后放到你的 private layer 中 local 文件夹下面,比如:

/my-private-layer/local/my-package/my-package.el

ps:这个文件夹是可以用 git 版本控制的。

1 个赞

有道理!听您这么讲,我感觉明朗了许多。

我在syl20bnr/spacemacs中搜索了一下google-translate, 发现其配置是在 spacemacs/layers/+spacemacs/spacemacs-language/packages.el里(话说有别的方法快速定位package所属的layer吗?):

(setq spacemacs-language-packages
      '((define-word :toggle (not (bound-and-true-p osx-use-dictionary-app)))
       google-translate))

您的意思是这样改吧:

(setq spacemacs-language-packages
      '((define-word :toggle (not (bound-and-true-p osx-use-dictionary-app)))
       (google-translate:location local)))

然后把google-translate 放在 .spacemacs.d/private/local/ 下面,单独用git控制,我看了一下.spacemacs.d下的.gitignore,它确实不控制private这个目录。

应该是

(google-translate :location local)

冒号的位置不对

但是这个 layer 不是 private layer,这样做应该不行的

应该是可以的,你参考一下 python layer,它用了几个 local package

哦,忘了空格了。

我先试试看

google-translate 好像是个多文件的包?

上面的方法好像只适用于单文件的包,多文件暂时还不支持。

但是我注意到最近有人 PR 解决了这一问题,只是暂时还没有 merge。你可以试用一下:

https://github.com/syl20bnr/spacemacs/pull/8718

2 个赞

我靠,好复杂呀。。。。

自己 fork 一份不好和源 package 同步,我是用 with-eval-after-load 修改特定的代码

不建议直接改插件代码。用advice或其他手段修改。如果是bug就直接提issue,就算是feature request也不用顾虑。

2 个赞

确实,但是上面的方法也可以用于维护自己写的包,我就是这么干的。

其实不麻烦,可以两个本地分支 upstreammasterupstream 的 remote 设为上游 repo (比如我就将 upstream 的 remote 设为 spacemacs 的 develop 分支)。 master 分支作为你的主力分支,它的 remote 设为你 fork 的repo。每次 upstream 更新后,rebase 一下 master 分支就好了,用 magit 根本不费什么事。这样做还有一个好处就是方便向 spacemacs 提交 PR

因为 org 的代码太长了,我 hack org 的时候连 with-eval-after-load 也没用,直接用正则搜索替换。缺点是每次更新 org 后都要重新运行一下。不过我现在想想,是不是也应该 fork 一份 org-mode 到 github 上。

我说的就是,上游有更新,你得手动去更新,如果 hack 的包多了,很难和上游保持同步;用 with-eval-after-load 直接用 Spacemacs 的 update package 功能就可以了

请问能解释下advice手段吗?

“很难和上游保持同步”

我协作开发经验不足。请问如果自己hack的部分不合并到源分支(PR尚未被采纳是不是就是这种情况?),那是不是根本没法同步?应该存在冲突了吧

这是论坛中已有的范例。adviace用于在原函数运行前/后添加一些东西,也可以用来覆盖原函数,好处是随时控制是否开启 advice。详细用法请C-h f advice-add RET查看文档。

在有 hook 可以用的时候优先用hook,如无必要不建议在写 package 的时候用 advice。

2 个赞