company-yasnippet-autoparens 1.0发布 (让company自动提示带括号的过程调用 19/2/15更新)

你的意思大概是,函数的元信息(比如:函数有几个参数之类的)也应该显示在列表里。

我认为这个功能普通snippet就能做到的,因为它是静态的(当然我们一般不会用snippet去这种事情,不然的话需要同步snippet和库函数的文档注释是很麻烦的)。

snippet只负责处理和语言相关的语法,并不处理函数的元信息。


company-yasnippet-autoparens 的目的仅仅是对你输入的任意symbol加括号,他不做代码分析(因为lisp大部分都是动态语言,不需要代码分析)

实际上,如果你使用的是静态语言(假如存在一个纯静态类型的lisp语言),company-yasnippet-autoparens 可能就没什么用武之地了。因为静态语言一般都有配套的代码分析器,它可以分析出你当前指针所在位置必须是一个过程调用,而不是一个普通symbol。于是它就可以弹出一个列表显示所有在这里可以调用的过程,这些过程显然都必须是(foo var1 var2)这种形式,而且带文档说明和参数列表等。

C-hv company-completion-finished-hook

你不需要弄一个backend

company-lsp就是在从lsp服务器端获取语法信息后,用snippet展开带签名的函数调用

根本不需要同步snippet还有文档注释,只需要获取一个参数列表的签名就行了,像eldoc一样

ELISP> (substring-no-properties (elisp-get-fnsym-args-string 'car))
"car: (LIST)"

yasnippet完全可以动态展开snippet

(yas-expand-snippet "(car ${1:cons})$0")

同理也不需要做代码分析

你觉得是就是? :zipper_mouth_face:

1 个赞
(defun expand-snippet-from-symfn (symfn)
  (when (or (fboundp symfn)
            (macrop symfn))
    (cl-destructuring-bind
        (name body
              &aux
              (arglist (split-string
                        (string-remove-prefix
                         "("
                         (string-remove-suffix
                          ")" body)) " "))
              (counter 0))
        (thread-first symfn
          (elisp-get-fnsym-args-string)
          (substring-no-properties)
          (split-string ": "))
      (yas-expand-snippet
       (format "(%s %s)$0"
               name
               (apply #'concat
                      (cl-loop
                       for arg in arglist
                       unless (member arg '("&optional"
                                            "&rest"))
                       collect (format "${%d:%s} " (cl-incf counter) arg))))))))

先敲了个初版的,有空改一下给你PR

用dash一时爽,一直用dash一直爽

(defun expand-snippet-from-symfn (symfn)
  (when (or (fboundp symfn)
            (macrop symfn))
    (-let* (((name body) (-> symfn
                             (elisp-get-fnsym-args-string)
                             (substring-no-properties)
                             (split-string ": ")))
            (arglist (->> body
                          (s-chop-prefix "(")
                          (s-chop-suffix ")")
                          (s-split " ")))
            (counter 0))
      (-as-> arglist result
             (--remove (member it '("&optional" "&rest")) result)
             (--map (format "${%d:%s}" (setq counter (1+ counter)) it)
                    result)
             (s-join " " result)
             (yas-expand-snippet (format "(%s %s)$0" name result))))))

我明白你的意思了。

可以抽象一个hook,让外部使用的人去接这个hook:

  1. 如果使用的是elisp就调用elisp-get-fnsym-args-string

  2. 如果是其他方言,可能需要去调用一个语言服务

  3. 如果没有语言服务,可能需要自己做一个简单的过程 扫描函数签名和注释。大部分方言的函数签名是一样的,除了define 和 defun 还有lambda形式,因此理论上可以做成通用库。。。

不过是不是会增加复杂性,我觉得还有必要进一步讨论。

直接打括号的复杂性为 1

1 个赞

你又不用其他lisp方言,杞人憂天做什麼。就算要做,讓解析參數列表後返回一個規範的數據格式不就成了?

Emacs Lisp的macro體和function體都是lambda

所以说,当真不考虑 projectional editor 一定要用手撸?

没有GUI的可怎么办

初学者表示, 用dash确实爽啊, 但是不熟悉 读得晕头转向。。。

整半天就是为了补全一个扩号?

我现在觉得 yasnippet 用来做自动补全就是一个错误!!!

以 c 为例

main<tab>

补全为

int main(int argc, char *argv[])
{
  |光标在此  
  return 0;
}

再来

incs<tab>

补全为

#include <|光标在此>

发现问题所在了吗?

一方面,我们为了少敲几个字破坏了““心流”,我们在尝试记住并使用一种方言(像前面的 incs), 这就有点得不偿失了。 另一方面,有一点违反直觉,一般来说补全都是在我们输入的内容后追加补全的内容,但是 像前面的例子,它在我们输入的 main 前面补了一个 int

我现在是尝试着将 yasnippet 当做一个本子,有意识地去查询并插入,像下面这样子: output-2019-02-14-17%3A30%3A04

关 GUI 啥事,拿 curse 写个 display backend 不就有了

并没有看出你所说的发现问题。

另外, company-yasnippet-autoparens 解决的是Lisp语言里独有的问题,C语言里根本不存在我说的那个问题。

我用其他lisp方言,比如:racket 以及由racket衍生出来的其他方言(比如:typed-racket)

确实可以考虑给个Hook,用来显示参数列表。

用 projectional editor 就是要换编辑器了。。。

现在大部分Lisp语言编辑器的前端都是做在Emacs上的(比如:racket-mode)。你用projectional editor就相当于也要做这样前端。

除此之外,Emacs确实有它自己的优势,比如:

Emacs作为文本编辑器可以灵活copy-paste,projectional editor 相对就显得比较笨重

Emacs支持多语言混合编程+文学编程,projectional editor 不支持

Emacs支持多backend完成列表,它可以把非语义的相关知识也作为完成列表,这个功能连大部分IDE都没有。

Projectional 做完后端就相当于已经有了高亮,补全,跳转,引用等前端提供的功能,Emacs 并没有提供更多的功能。

Projectional 不会阻止用户 copy paste 任意文本。甚至支持表格,公式之类的富文本。

Projetional 不支持混合语言编程才是无稽之谈,甚至可以做到在一种语言里任意嵌套另外一种语言。先不说对于真正原教旨的 WEB 来说 Org mode 的文学编程是假的文学编程,对于一个成熟的 IDE 开发套件要实现 Python Notebook 那样的功能并不难,不用忍受 Org 基于纯文本的设计带来各种 bug 和性能问题以及 Emacs Lisp 缺少 OOP 带来的扩展限制就是一大优点。

Emacs 只提供了补全的界面,就算是非编程语言相关的后端也都在那里,有什么不可行的吗?

1 个赞

抱歉 我歪楼请教一个问题

请问 Common Lisp 和 Haskell 各自有什么优缺点、异同点 及 各自适用于或已成功用于的领域

虽说学会了一门可以更容易掌握另一门 但毕竟精力有限

还望赐教

这个用法真是清奇…一般我使用yas都是prefix能有多短就多短,不让它在company里出现。比如python里

  1. m->#include ... int main ... return ...
  2. h-> # -*- coding: utf-8 -*-
  3. a-> import argparse ... def parse_args() ... parser = argparse.ArgumentParser() ...$0... args = parser.parse_args()... return args
  4. th-> import torch...from torch import nn...from torch.nn import functional as F

难道用yas不是就为了少打字吗。。所以我理解不了还要用company下拉菜单去选个snippet这种操作,这个操作还要是补全个括号…

说prefix太短记不住的,实在想不到天天用的怎么会记不住…

1 个赞

这两门都是很复杂的学问,Lisp 有六十多年的研究在后面,Haskell 虽然也就二十来年,但是有更为深厚的数理逻辑在后面。

这样说,除非出于极大的兴趣,基本上都不会深入这两个语言,零碎时间花个半年读读书两门就都会写了。我不觉得会有什么吃亏或者值得纠结的。

这两门都要论外,反而是完全忘记怎么编程以后更容易学。

或者你也可以等看完 TAOCP 前两本再看。

我发现我跳进了一个循环

要想看好算法 就得有数理逻辑的知识

而要弄懂数理逻辑的计算机实现 你得知道算法

我得改改深究细节的毛病