Documentation ¶
Overview ¶
Package elisp provides a backend for Emacs Lisp using Cask.
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var ElispBackend = api.LanguageBackend{ Name: "elisp-cask", Specfile: "Cask", Lockfile: "packages.txt", IsAvailable: elispCaskIsAvailable, FilenamePatterns: elispPatterns, Quirks: api.QuirksNotReproducible, GetPackageDir: func() string { return ".cask" }, Search: func(query string) []api.PkgInfo { tmpdir, err := os.MkdirTemp("", "elpa") if err != nil { util.DieIO("%s", err) } defer os.RemoveAll(tmpdir) code := fmt.Sprintf( "(eval '(progn %s) t)", util.GetResource("/elisp/elpa-search.el"), ) code = strings.Replace(code, "~", "`", -1) outputB := util.GetCmdOutput([]string{ "emacs", "-Q", "--batch", "--eval", code, tmpdir, "search", query, }) var results []api.PkgInfo if err := json.Unmarshal(outputB, &results); err != nil { util.DieProtocol("%s", err) } return results }, Info: func(name api.PkgName) api.PkgInfo { tmpdir, err := os.MkdirTemp("", "elpa") if err != nil { util.DieIO("%s", err) } defer os.RemoveAll(tmpdir) code := fmt.Sprintf( "(eval '(progn %s) t)", util.GetResource("/elisp/elpa-search.el"), ) code = strings.Replace(code, "~", "`", -1) outputB := util.GetCmdOutput([]string{ "emacs", "-Q", "--batch", "--eval", code, tmpdir, "info", string(name), }) var info api.PkgInfo if err := json.Unmarshal(outputB, &info); err != nil { util.DieProtocol("%s", err) } return info }, Add: func(ctx context.Context, pkgs map[api.PkgName]api.PkgSpec, projectName string) { span, ctx := tracer.StartSpanFromContext(ctx, "elisp add") defer span.Finish() contentsB, err := os.ReadFile("Cask") var contents string if os.IsNotExist(err) { contents = `(source melpa) (source gnu) (source org) ` } else if err != nil { util.DieIO("Cask: %s", err) } else { contents = string(contentsB) } if len(contents) > 0 && contents[len(contents)-1] != '\n' { contents += "\n" } for name, spec := range pkgs { contents += fmt.Sprintf(`(depends-on "%s"`, name) if spec != "" { contents += fmt.Sprintf(" %s", spec) } contents += ")\n" } contentsB = []byte(contents) util.ProgressMsg("write Cask") util.TryWriteAtomic("Cask", contentsB) }, Remove: func(ctx context.Context, pkgs map[api.PkgName]bool) { span, ctx := tracer.StartSpanFromContext(ctx, "elisp remove") defer span.Finish() contentsB, err := os.ReadFile("Cask") if err != nil { util.DieIO("Cask: %s", err) } contents := string(contentsB) for name := range pkgs { contents = regexp.MustCompile( fmt.Sprintf( `(?m)^ *\(depends-on +"%s".*\)\n?$`, regexp.QuoteMeta(string(name)), ), ).ReplaceAllLiteralString(contents, "") } contentsB = []byte(contents) util.ProgressMsg("write Cask") util.TryWriteAtomic("Cask", contentsB) }, Install: func(ctx context.Context) { span, ctx := tracer.StartSpanFromContext(ctx, "cask install") defer span.Finish() util.RunCmd([]string{"cask", "install"}) outputB := util.GetCmdOutput( []string{"cask", "eval", util.GetResource( "/elisp/cask-list-installed.el", )}, ) util.ProgressMsg("write packages.txt") util.TryWriteAtomic("packages.txt", outputB) }, ListSpecfile: func(mergeAllGroups bool) map[api.PkgName]api.PkgSpec { outputB := util.GetCmdOutput( []string{"cask", "eval", util.GetResource( "/elisp/cask-list-specfile.el", )}, ) pkgs := map[api.PkgName]api.PkgSpec{} for _, line := range strings.Split(string(outputB), "\n") { if line == "" { continue } fields := strings.SplitN(line, "=", 2) if len(fields) != 2 { util.DieProtocol("unexpected output, expected name=spec: %s", line) } name := api.PkgName(fields[0]) spec := api.PkgSpec(fields[1]) pkgs[name] = spec } return pkgs }, ListLockfile: func() map[api.PkgName]api.PkgVersion { contentsB, err := os.ReadFile("packages.txt") if err != nil { util.DieIO("packages.txt: %s", err) } contents := string(contentsB) r := regexp.MustCompile(`(.+)=(.+)`) pkgs := map[api.PkgName]api.PkgVersion{} for _, match := range r.FindAllStringSubmatch(contents, -1) { name := api.PkgName(match[1]) version := api.PkgVersion(match[2]) pkgs[name] = version } return pkgs }, GuessRegexps: util.Regexps([]string{ `\(\s*require\s*'\s*([^)[:space:]]+)[^)]*\)`, }), Guess: func(ctx context.Context) (map[string][]api.PkgName, bool) { span, ctx := tracer.StartSpanFromContext(ctx, "elisp guess") defer span.Finish() r := regexp.MustCompile( `\(\s*require\s*'\s*([^)[:space:]]+)[^)]*\)`, ) required := map[string]bool{} for _, match := range util.SearchRecursive(r, elispPatterns) { required[match[1]] = true } if len(required) == 0 { return map[string][]api.PkgName{}, true } r = regexp.MustCompile( `\(\s*provide\s*'\s*([^)[:space:]]+)[^)]*\)`, ) provided := map[string]bool{} for _, match := range util.SearchRecursive(r, elispPatterns) { provided[match[1]] = true } tempdir, err := os.MkdirTemp("", "epkgs") if err != nil { util.DieIO("%s", err) } defer os.RemoveAll(tempdir) url := "https://github.com/emacsmirror/epkgs/raw/master/epkg.sqlite" epkgs := filepath.Join(tempdir, "epkgs.sqlite") util.DownloadFile(epkgs, url) clauses := []string{} for feature := range required { if strings.ContainsAny(feature, `\'`) { continue } if provided[feature] { continue } clauses = append(clauses, fmt.Sprintf("feature = '%s'", feature)) } if len(clauses) == 0 { return map[string][]api.PkgName{}, true } where := strings.Join(clauses, " OR ") query := fmt.Sprintf("SELECT package FROM provided PR WHERE (%s) "+ "AND NOT EXISTS (SELECT 1 FROM builtin_libraries B "+ "WHERE PR.feature = B.feature) "+ "AND NOT EXISTS (SELECT 1 FROM packages PK "+ "WHERE PR.package = PK.name AND PK.class = 'builtin');", where, ) output := string(util.GetCmdOutput([]string{"sqlite3", epkgs, query})) r = regexp.MustCompile(`"(.+?)"`) names := map[string][]api.PkgName{} for _, match := range r.FindAllStringSubmatch(output, -1) { name := match[1] names[name] = []api.PkgName{api.PkgName(name)} } return names, true }, InstallReplitNixSystemDependencies: nix.DefaultInstallReplitNixSystemDependencies, }
ElispBackend is the UPM language backend for Emacs Lisp using Cask.
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.