zyedidia-micro-6a62575/0000775000175000017510000000000015125206537014243 5ustar nileshnileshzyedidia-micro-6a62575/tools/0000775000175000017510000000000015125206537015403 5ustar nileshnileshzyedidia-micro-6a62575/tools/vendor-src.sh0000775000175000017510000000014215125206537020021 0ustar nileshnileshcd ../.. tar czf "$1".tar.gz micro zip -rq "$1".zip micro mv "$1".tar.gz micro mv "$1".zip micro zyedidia-micro-6a62575/tools/update-nightly-tag.sh0000775000175000017510000000050615125206537021452 0ustar nileshnileshcommitID=$(git rev-parse --short HEAD) echo "Moving tag" hub push origin :refs/tags/nightly git tag -f nightly $commitID hub push --tags MESSAGE=$'Nightly build\n\nAutogenerated nightly build of micro' echo "Creating new release" hub release create nightly \ --prerelease \ --draft=false \ --message "$MESSAGE." zyedidia-micro-6a62575/tools/testgen.go0000664000175000017510000001364715125206537017416 0ustar nileshnilesh//go:build ignore package main import ( "fmt" "log" "os" "regexp" "strings" "github.com/robertkrimen/otto/ast" "github.com/robertkrimen/otto/parser" ) type walker struct { nodes []ast.Node } func (w *walker) Enter(node ast.Node) ast.Visitor { w.nodes = append(w.nodes, node) return w } func (w *walker) Exit(node ast.Node) { } func getAllNodes(node ast.Node) []ast.Node { w := &walker{} ast.Walk(w, node) return w.nodes } func getCalls(node ast.Node, name string) []*ast.CallExpression { nodes := []*ast.CallExpression{} for _, n := range getAllNodes(node) { if ce, ok := n.(*ast.CallExpression); ok { var calleeName string switch callee := ce.Callee.(type) { case *ast.Identifier: calleeName = callee.Name case *ast.DotExpression: calleeName = callee.Identifier.Name default: continue } if calleeName == name { nodes = append(nodes, ce) } } } return nodes } func getPropertyValue(node ast.Node, key string) ast.Expression { for _, p := range node.(*ast.ObjectLiteral).Value { if p.Key == key { return p.Value } } return nil } type operation struct { startLine int startColumn int endLine int endColumn int text []string } type check struct { before []string operations []operation after []string } type test struct { description string checks []check } func stringSliceToGoSource(slice []string) string { var b strings.Builder b.WriteString("[]string{\n") for _, s := range slice { b.WriteString(fmt.Sprintf("%#v,\n", s)) } b.WriteString("}") return b.String() } func testToGoTest(test test, name string) string { var b strings.Builder b.WriteString("func Test") b.WriteString(name) b.WriteString("(t *testing.T) {\n") for _, c := range test.checks { b.WriteString("check(\n") b.WriteString("t,\n") b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.before))) b.WriteString("[]operation{\n") for _, op := range c.operations { b.WriteString("operation{\n") b.WriteString(fmt.Sprintf("start: Loc{%v, %v},\n", op.startColumn, op.startLine)) b.WriteString(fmt.Sprintf("end: Loc{%v, %v},\n", op.endColumn, op.endLine)) b.WriteString(fmt.Sprintf("text: %v,\n", stringSliceToGoSource(op.text))) b.WriteString("},\n") } b.WriteString("},\n") b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.after))) b.WriteString(")\n") } b.WriteString("}\n") return b.String() } func nodeToStringSlice(node ast.Node) []string { var result []string for _, s := range node.(*ast.ArrayLiteral).Value { result = append(result, s.(*ast.StringLiteral).Value) } return result } func nodeToStringSlice2(node ast.Node) []string { var result []string for _, o := range node.(*ast.ArrayLiteral).Value { result = append(result, getPropertyValue(o, "text").(*ast.StringLiteral).Value) } return result } func nodeToInt(node ast.Node) int { return int(node.(*ast.NumberLiteral).Value.(int64)) } func getChecks(node ast.Node) []check { checks := []check{} for _, ce := range getCalls(node, "testApplyEdits") { if len(ce.ArgumentList) != 3 { // Wrong function continue } before := nodeToStringSlice2(ce.ArgumentList[0]) after := nodeToStringSlice2(ce.ArgumentList[2]) var operations []operation for _, op := range ce.ArgumentList[1].(*ast.ArrayLiteral).Value { args := getPropertyValue(op, "range").(*ast.NewExpression).ArgumentList operations = append(operations, operation{ startLine: nodeToInt(args[0]) - 1, startColumn: nodeToInt(args[1]) - 1, endLine: nodeToInt(args[2]) - 1, endColumn: nodeToInt(args[3]) - 1, text: []string{getPropertyValue(op, "text").(*ast.StringLiteral).Value}, }) } checks = append(checks, check{before, operations, after}) } for _, ce := range getCalls(node, "testApplyEditsWithSyncedModels") { if len(ce.ArgumentList) > 3 && ce.ArgumentList[3].(*ast.BooleanLiteral).Value { // inputEditsAreInvalid == true continue } before := nodeToStringSlice(ce.ArgumentList[0]) after := nodeToStringSlice(ce.ArgumentList[2]) var operations []operation for _, op := range getCalls(ce.ArgumentList[1], "editOp") { operations = append(operations, operation{ startLine: nodeToInt(op.ArgumentList[0]) - 1, startColumn: nodeToInt(op.ArgumentList[1]) - 1, endLine: nodeToInt(op.ArgumentList[2]) - 1, endColumn: nodeToInt(op.ArgumentList[3]) - 1, text: nodeToStringSlice(op.ArgumentList[4]), }) } checks = append(checks, check{before, operations, after}) } return checks } func getTests(node ast.Node) []test { tests := []test{} for _, ce := range getCalls(node, "test") { description := ce.ArgumentList[0].(*ast.StringLiteral).Value body := ce.ArgumentList[1].(*ast.FunctionLiteral).Body checks := getChecks(body) if len(checks) > 0 { tests = append(tests, test{description, checks}) } } return tests } func main() { var tests []test for _, filename := range os.Args[1:] { source, err := os.ReadFile(filename) if err != nil { log.Fatalln(err) } program, err := parser.ParseFile(nil, "", source, parser.IgnoreRegExpErrors) if err != nil { log.Fatalln(err) } tests = append(tests, getTests(program)...) } if len(tests) == 0 { log.Fatalln("no tests found!") } fmt.Println("// This file is generated from VSCode model tests by the testgen tool.") fmt.Println("// DO NOT EDIT THIS FILE BY HAND; your changes will be overwritten!\n") fmt.Println("package buffer") fmt.Println(`import "testing"`) re := regexp.MustCompile(`[^\w]`) usedNames := map[string]bool{} for _, test := range tests { name := strings.Title(strings.ToLower(test.description)) name = re.ReplaceAllLiteralString(name, "") if name == "" { name = "Unnamed" } if usedNames[name] { for i := 2; ; i++ { newName := fmt.Sprintf("%v_%v", name, i) if !usedNames[newName] { name = newName break } } } usedNames[name] = true fmt.Println(testToGoTest(test, name)) } } zyedidia-micro-6a62575/tools/remove-nightly-assets.go0000664000175000017510000000141615125206537022205 0ustar nileshnilesh//go:build ignore package main import ( "fmt" "io" "net/http" "os/exec" "strings" "github.com/micro-editor/json5" ) func main() { resp, err := http.Get("https://api.github.com/repos/zyedidia/micro/releases") if err != nil { fmt.Println(err.Error()) return } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) var data any err = json5.Unmarshal(body, &data) for _, val := range data.([]any) { m := val.(map[string]any) releaseName := m["name"].(string) assets := m["assets"].([]any) for _, asset := range assets { assetInfo := asset.(map[string]any) url := assetInfo["url"].(string) if strings.Contains(strings.ToLower(releaseName), "nightly") { cmd := exec.Command("hub", "api", "-X", "DELETE", url) cmd.Run() } } } } zyedidia-micro-6a62575/tools/release.sh0000775000175000017510000000232615125206537017365 0ustar nileshnilesh# This script creates releases on Github for micro # You must have the correct Github access token to run this script # $1 is the title, $2 is the description commitID=$(git rev-parse HEAD) tag="v$1" echo "Creating tag" git tag $tag $commitID hub push --tags NL=$'\n' echo "Cross compiling binaries" ./cross-compile.sh $1 mv ../binaries . echo "Creating new release" hub release create $tag \ --message "$1${NL}${NL}$2" \ --attach "binaries/micro-$1-osx.tar.gz" \ --attach "binaries/micro-$1-macos-arm64.tar.gz" \ --attach "binaries/micro-$1-linux64.tar.gz" \ --attach "binaries/micro-$1-linux64-static.tar.gz" \ --attach "binaries/micro-$1-amd64.deb" \ --attach "binaries/micro-$1-linux32.tar.gz" \ --attach "binaries/micro-$1-linux-arm.tar.gz" \ --attach "binaries/micro-$1-linux-arm64.tar.gz" \ --attach "binaries/micro-$1-freebsd64.tar.gz" \ --attach "binaries/micro-$1-freebsd32.tar.gz" \ --attach "binaries/micro-$1-openbsd64.tar.gz" \ --attach "binaries/micro-$1-openbsd32.tar.gz" \ --attach "binaries/micro-$1-netbsd64.tar.gz" \ --attach "binaries/micro-$1-netbsd32.tar.gz" \ --attach "binaries/micro-$1-win64.zip" \ --attach "binaries/micro-$1-win32.zip" zyedidia-micro-6a62575/tools/pre-release.sh0000775000175000017510000000235115125206537020147 0ustar nileshnilesh# This script creates releases on Github for micro # You must have the correct Github access token to run this script # $1 is the title, $2 is the description commitID=$(git rev-parse HEAD) tag="v$1" echo "Creating tag" git tag $tag $commitID hub push --tags echo "Cross compiling binaries" ./cross-compile.sh $1 mv ../binaries . NL=$'\n' echo "Creating new release" hub release create $tag \ --prerelease \ --message "$1${NL}${NL}$2" \ --attach "binaries/micro-$1-osx.tar.gz" \ --attach "binaries/micro-$1-macos-arm64.tar.gz" \ --attach "binaries/micro-$1-linux64.tar.gz" \ --attach "binaries/micro-$1-linux64-static.tar.gz" \ --attach "binaries/micro-$1-amd64.deb" \ --attach "binaries/micro-$1-linux32.tar.gz" \ --attach "binaries/micro-$1-linux-arm.tar.gz" \ --attach "binaries/micro-$1-linux-arm64.tar.gz" \ --attach "binaries/micro-$1-freebsd64.tar.gz" \ --attach "binaries/micro-$1-freebsd32.tar.gz" \ --attach "binaries/micro-$1-openbsd64.tar.gz" \ --attach "binaries/micro-$1-openbsd32.tar.gz" \ --attach "binaries/micro-$1-netbsd64.tar.gz" \ --attach "binaries/micro-$1-netbsd32.tar.gz" \ --attach "binaries/micro-$1-win64.zip" \ --attach "binaries/micro-$1-win32.zip" zyedidia-micro-6a62575/tools/package-deb.sh0000775000175000017510000000057615125206537020075 0ustar nileshnileshcommand -v fpm > /dev/null && fpm -s dir -t deb -p micro-$1-amd64.deb --name micro --license mit --version $1 --deb-recommends xclip --description "A modern and intuitive terminal-based text editor" --after-install ./assets/packaging/deb/micro.postinst --before-remove ./assets/packaging/deb/micro.prerm ./micro=/usr/bin/micro ./assets/packaging/micro.1=/usr/share/man/man1/micro.1 zyedidia-micro-6a62575/tools/nightly-release.sh0000775000175000017510000000251615125206537021042 0ustar nileshnilesh# This script updates the nightly release on Github for micro # Must be run from inside the micro git repository commitID=$(git rev-parse --short HEAD) go run remove-nightly-assets.go echo "Cross compiling binaries" ./cross-compile.sh $1 mv ../binaries . MESSAGE=$'Nightly build\n\nAutogenerated nightly build of micro' echo "Updating release" hub release edit nightly \ --prerelease \ --draft=false \ --message "$MESSAGE (please DISREGARD the creation date of this Github release). Assets uploaded on $(date) for commit $commitID." \ --attach "binaries/micro-$1-osx.tar.gz" \ --attach "binaries/micro-$1-macos-arm64.tar.gz" \ --attach "binaries/micro-$1-linux64.tar.gz" \ --attach "binaries/micro-$1-linux64-static.tar.gz" \ --attach "binaries/micro-$1-amd64.deb" \ --attach "binaries/micro-$1-linux32.tar.gz" \ --attach "binaries/micro-$1-linux-arm.tar.gz" \ --attach "binaries/micro-$1-linux-arm64.tar.gz" \ --attach "binaries/micro-$1-freebsd64.tar.gz" \ --attach "binaries/micro-$1-freebsd32.tar.gz" \ --attach "binaries/micro-$1-openbsd64.tar.gz" \ --attach "binaries/micro-$1-openbsd32.tar.gz" \ --attach "binaries/micro-$1-netbsd64.tar.gz" \ --attach "binaries/micro-$1-netbsd32.tar.gz" \ --attach "binaries/micro-$1-win64.zip" \ --attach "binaries/micro-$1-win32.zip" zyedidia-micro-6a62575/tools/info-plist.go0000664000175000017510000000172215125206537020020 0ustar nileshnilesh//go:build ignore package main import ( "fmt" "os" "runtime" ) func main() { if runtime.GOOS != "darwin" { return } if len(os.Args) != 3 { panic("missing arguments") } if os.Args[1] != "darwin" { return } rawInfoPlist := ` CFBundleIdentifier io.github.micro-editor CFBundleName micro CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleShortVersionString ` + os.Args[2] + ` ` err := os.WriteFile("/tmp/micro-info.plist", []byte(rawInfoPlist), 0666) if err != nil { panic(err) } fmt.Println("-linkmode external -extldflags -Wl,-sectcreate,__TEXT,__info_plist,/tmp/micro-info.plist") } zyedidia-micro-6a62575/tools/cross-compile.sh0000775000175000017510000000571015125206537020524 0ustar nileshnilesh#!/bin/sh set -e VERSION="$1" if [ -z "$VERSION" ]; then VERSION="$(go run tools/build-version.go)" fi mkdir -p binaries mkdir -p micro-$VERSION cp LICENSE micro-$VERSION cp README.md micro-$VERSION cp LICENSE-THIRD-PARTY micro-$VERSION cp assets/packaging/micro.1 micro-$VERSION cp assets/packaging/micro.desktop micro-$VERSION cp assets/micro-logo-mark.svg micro-$VERSION/micro.svg create_artefact_generic() { mv micro micro-$VERSION/ tar -czf micro-$VERSION-$1.tar.gz micro-$VERSION sha256sum micro-$VERSION-$1.tar.gz > micro-$VERSION-$1.tar.gz.sha mv micro-$VERSION-$1.* binaries rm micro-$VERSION/micro } create_artefact_windows() { mv micro.exe micro-$VERSION/ zip -r -q -T micro-$VERSION-$1.zip micro-$VERSION sha256sum micro-$VERSION-$1.zip > micro-$VERSION-$1.zip.sha mv micro-$VERSION-$1.* binaries rm micro-$VERSION/micro.exe } # Mac echo "OSX 64" GOOS=darwin GOARCH=amd64 make build create_artefact_generic "osx" # Mac ARM64 echo "MacOS ARM64" GOOS=darwin GOARCH=arm64 make build create_artefact_generic "macos-arm64" # Linux echo "Linux 64" GOOS=linux GOARCH=amd64 make build if ./tools/package-deb.sh $VERSION; then sha256sum micro-$VERSION-amd64.deb > micro-$VERSION-amd64.deb.sha mv micro-$VERSION-amd64.* binaries fi create_artefact_generic "linux64" echo "Linux 64 fully static (same as linux64)" # It is kept for the next release only to support... # https://github.com/benweissmann/getmic.ro/blob/f90870e948afab8be9ec40884050044b59ed5b7c/index.sh#L197-L204 # ...and allow a fluent switch via: # https://github.com/benweissmann/getmic.ro/pull/40 GOOS=linux GOARCH=amd64 make build create_artefact_generic "linux64-static" echo "Linux 32" GOOS=linux GOARCH=386 make build create_artefact_generic "linux32" echo "Linux ARM 32" GOOS=linux GOARM=6 GOARCH=arm make build create_artefact_generic "linux-arm" echo "Linux ARM 64" GOOS=linux GOARCH=arm64 make build create_artefact_generic "linux-arm64" # Solaris echo "Solaris 64" GOOS=solaris GOARCH=amd64 make build create_artefact_generic "solaris64" # Illumos echo "Illumos 64" GOOS=illumos GOARCH=amd64 make build create_artefact_generic "illumos64" # NetBSD echo "NetBSD 64" GOOS=netbsd GOARCH=amd64 make build create_artefact_generic "netbsd64" echo "NetBSD 32" GOOS=netbsd GOARCH=386 make build create_artefact_generic "netbsd32" # OpenBSD echo "OpenBSD 64" GOOS=openbsd GOARCH=amd64 make build create_artefact_generic "openbsd64" echo "OpenBSD 32" GOOS=openbsd GOARCH=386 make build create_artefact_generic "openbsd32" # FreeBSD echo "FreeBSD 64" GOOS=freebsd GOARCH=amd64 make build create_artefact_generic "freebsd64" echo "FreeBSD 32" GOOS=freebsd GOARCH=386 make build create_artefact_generic "freebsd32" # Windows echo "Windows 64" GOOS=windows GOARCH=amd64 make build create_artefact_windows "win64" echo "Windows ARM 64" GOOS=windows GOARCH=arm64 make build create_artefact_windows "win-arm64" echo "Windows 32" GOOS=windows GOARCH=386 make build create_artefact_windows "win32" rm -rf micro-$VERSION zyedidia-micro-6a62575/tools/compile-linux.sh0000775000175000017510000000246215125206537020533 0ustar nileshnileshcd .. mkdir -p binaries mkdir -p micro-$1 cp LICENSE micro-$1 cp README.md micro-$1 cp LICENSE-THIRD-PARTY micro-$1 HASH="$(git rev-parse --short HEAD)" VERSION="$(go run tools/build-version.go)" DATE="$(go run tools/build-date.go)" ADDITIONAL_GO_LINKER_FLAGS="$(go run tools/info-plist.go $VERSION)" echo "Linux 64" GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$DATE'" -o micro-$1/micro ./cmd/micro tar -czf micro-$1-linux64.tar.gz micro-$1 mv micro-$1-linux64.tar.gz binaries echo "Linux 32" GOOS=linux GOARCH=386 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$DATE'" -o micro-$1/micro ./cmd/micro tar -czf micro-$1-linux32.tar.gz micro-$1 mv micro-$1-linux32.tar.gz binaries echo "Linux arm 32" GOOS=linux GOARM=6 GOARCH=arm go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$DATE'" -o micro-$1/micro ./cmd/micro tar -czf micro-$1-linux-arm.tar.gz micro-$1 mv micro-$1-linux-arm.tar.gz binaries echo "Linux arm 64" GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X main.Version=$1 -X main.CommitHash=$HASH -X 'main.CompileDate=$DATE'" -o micro-$1/micro ./cmd/micro tar -czf micro-$1-linux-arm64.tar.gz micro-$1 mv micro-$1-linux-arm64.tar.gz binaries rm -rf micro-$1 zyedidia-micro-6a62575/tools/build-version.go0000664000175000017510000000374015125206537020520 0ustar nileshnilesh//go:build ignore package main import ( "fmt" "log" "os/exec" "strings" "github.com/blang/semver" ) func getTag(match ...string) (string, *semver.PRVersion) { args := append([]string{ "describe", "--tags", }, match...) if tag, err := exec.Command("git", args...).Output(); err != nil { return "", nil } else { tagParts := strings.Split(string(tag), "-") if len(tagParts) == 3 { ahead, err := semver.NewPRVersion(tagParts[1]) if err == nil { return tagParts[0], &ahead } log.Printf("semver.NewPRVersion(%s): %v", tagParts[1], err) } else if len(tagParts) == 4 { ahead, err := semver.NewPRVersion(tagParts[2]) if err == nil { return tagParts[0] + "-" + tagParts[1], &ahead } log.Printf("semver.NewPRVersion(%s): %v", tagParts[2], err) } return string(tag), nil } } func main() { // Find the last vX.X.X Tag and get how many builds we are ahead of it. versionStr, ahead := getTag("--match", "v*") version, err := semver.ParseTolerant(versionStr) if err != nil { // no version tag found so just return what ever we can find. log.Printf("semver.ParseTolerant(%s): %v", versionStr, err) fmt.Println("0.0.0-unknown") return } if ahead == nil { // Seems that we are going to build a release. // So the version number should already be correct. fmt.Println(version.String()) return } // Get the tag of the current revision. tag, _ := getTag("--exact-match") // If we don't have any tag assume "dev" if tag == "" || strings.HasPrefix(tag, "nightly") { tag = "dev" } // Get the most likely next version: if !strings.Contains(version.String(), "rc") { version.Patch = version.Patch + 1 } if pr, err := semver.NewPRVersion(tag); err == nil { // append the tag as pre-release name version.Pre = append(version.Pre, pr) } else { log.Printf("semver.NewPRVersion(%s): %v", tag, err) } // append how many commits we are ahead of the last release version.Pre = append(version.Pre, *ahead) fmt.Println(version.String()) } zyedidia-micro-6a62575/tools/build-date.go0000664000175000017510000000066515125206537017753 0ustar nileshnilesh//go:build ignore package main import ( "fmt" "os" "strconv" "time" ) func main() { var buildTime time.Time epoch := os.Getenv("SOURCE_DATE_EPOCH") if epoch != "" { i, err := strconv.Atoi(epoch) if err != nil { fmt.Errorf("SOURCE_DATE_EPOCH is not a valid integer") os.Exit(1) } buildTime = time.Unix(int64(i), 0) } else { buildTime = time.Now().Local() } fmt.Println(buildTime.Format("January 02, 2006")) } zyedidia-micro-6a62575/snapcraft.yaml0000664000175000017510000000154415125206537017114 0ustar nileshnileshname: micro summary: A modern and intuitive terminal-based text editor description: | Micro is a terminal-based text editor that aims to be easy to use and intuitive, while also taking advantage of the full capabilities of modern terminals. confinement: classic adopt-info: micro base: core20 apps: micro: command: bin/micro parts: micro: source: . source-type: git plugin: go build-packages: [make] build-attributes: [no-patchelf] override-pull: | snapcraftctl pull version="$(go run $SNAPCRAFT_PART_SRC/tools/build-version.go)" [ -n "$(echo $version | grep "dev")" ] && grade=devel || grade=stable snapcraftctl set-version "$version" snapcraftctl set-grade "$grade" override-build: | make build-tags mkdir $SNAPCRAFT_PART_INSTALL/bin mv ./micro $SNAPCRAFT_PART_INSTALL/bin/ zyedidia-micro-6a62575/runtime/0000775000175000017510000000000015125206537015726 5ustar nileshnileshzyedidia-micro-6a62575/runtime/syntax/0000775000175000017510000000000015125206537017254 5ustar nileshnileshzyedidia-micro-6a62575/runtime/syntax/zsh.yaml0000664000175000017510000000412215125206537020743 0ustar nileshnileshfiletype: zsh detect: filename: "(\\.zsh$|\\.?(zshenv|zprofile|zshrc|zlogin|zlogout)$)" header: "^#!.*/(env +)?zsh( |$)" rules: ## Numbers - constant.number: "\\b[0-9]+\\b" ## Conditionals and control flow - statement: "\\b(always|break|bye|case|continue|disown|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while)\\b" - statement: "(\\{|\\}|\\(|\\)|\\;|\\]|\\[|`|\\\\|\\$|<|>|!|=|&|\\|)" ## Conditional flags - special: "-[Ldefgruwx]\\b" - special: "-(eq|ne|gt|lt|ge|le|s|n|z)\\b" ## Bash-inherited - statement: "\\b((un)?alias|bindkey|builtin|cd|declare|eval|exec|export|jobs|let|popd|pushd|set|source|typeset|umask|unset)\\b" ## ZSH-specific - type: "\\b(add-zsh-hook|autoload|chdir|compinit|dirs|(dis|en)able|echotc|emulate|print|prompt(init)?|(un)?setopt|zle|zmodload|zstyle|whence)\\b" ## Common linux commands - statement: "\\b((g|ig)?awk|find|\\w{0,4}grep|kill|killall|\\w{0,4}less|make|pkill|sed|tar)\\b" ## Coreutils commands - statement: "\\b(base64|basename|cat|chcon|chgrp|chmod|chown|chroot|cksum|comm|cp|csplit|cut|date|dd|df|dir|dircolors|dirname|du|echo|env|expand|expr|factor|false|fmt|fold|head|hostid|id|install|join|link|ln|logname|ls|md5sum|mkdir|mkfifo|mknod|mktemp|mv|nice|nl|nohup|nproc|numfmt|od|paste|pathchk|pinky|pr|printenv|printf|ptx|pwd|readlink|realpath|rm|rmdir|runcon|seq|(sha1|sha224|sha256|sha384|sha512)sum|shred|shuf|sleep|sort|split|stat|stdbuf|stty|sum|sync|tac|tail|tee|test|timeout|touch|tr|true|truncate|tsort|tty|uname|unexpand|uniq|unlink|users|vdir|wc|who|whoami|yes)\\b" ## Function definition - identifier: "^\\s+(function\\s+)[0-9A-Z_]+\\s+\\(\\)" # (i) ## Variables - identifier: "\\$\\{?[0-9A-Z_!@#$*?-]+\\}?" #(i) - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" rules: [] - comment: start: "(^|\\s)#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/zscript.yaml0000664000175000017510000000466315125206537021647 0ustar nileshnileshfiletype: zscript # Loosely based on the csharp.yaml definition # (?i) on everything because ZScript isn't case sensitive detect: filename: "(?i)\\.z(c|sc)$" rules: # ZScript only has one preprocessor directive and a required engine version declaration - preproc: "(?i)#include" - preproc: "(?i)version" # State labels ("goto" word overridden by state logic rule below) - symbol.tag: "(?i)[a-z0-9.]+:" - symbol.tag: "(?i)goto [a-z0-9]+[\\+0-9]*" # Classes - identifier.class: "(?i)class +[a-z0-9_]+ *((:) +[a-z0-9.]+)?" # Functions (open paren overridden by symbol.brackets rule because perl regex apparently doesn't support postive lookahead) - identifier: "(?i)[\\.]*[a-z0-9_]+[ ]*[(]+" # Variable types - type: "(?i)\\b(actor|object|vector2|vector3|name|string|color|sound|void|double|bool|int|float|float64|uint8|uint16|uint|int8|int16|TextureID|SpriteID|Array|voidptr|short|action|state|statelabel)\\b" # Keywords - statement: "(?i)\\b(class|default|private|static|native|return|if|else|for|while|do|deprecated|null|readonly|true|false|struct|extend|clearscope|vararg|ui|play|virtual|virtualscope|meta|Property|in|out|states|override|super|is|let|const|replaces|protected|self|abstract|enum|switch|case)\\b" # State logic keywords - special: "(?i)\\b(goto|loop|stop|break|continue|fail)\\b" # Symbols - symbol.operator: "[\\-+/*=<>?:!~%&|]" - symbol.brackets: "[(){}]|\\[|\\]" # Constants - constant.bool: "(?i)(\\b(true|false)\\b|NULL)" - constant.number: "(?i)\\b([0-9][.]*[0-9]*)+?\\b" - constant.number: "(?i)\\b(0x[A-Fa-f0-9_]+)?\\b" - constant.number: "(?i)\\b(0b[0-1_]+)[FL]?\\b" #- constant.number: "(?i)\\b(([0-9][.]*[0-9]*)+|0x[A-Fa-f0-9_]+|0b[0-1_]+)[FL]?\\b" # Strings - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([btnfr]|'|\\\"|\\\\)" - constant.specialChar: "\\\\u[A-Fa-f0-9]{4}" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\([btnfr]|'|\\\"|\\\\)" - constant.specialChar: "\\\\u[A-Fa-f0-9]{4}" # Comments - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/zig.yaml0000664000175000017510000000334715125206537020740 0ustar nileshnileshfiletype: zig detect: filename: "\\.z(ig|on)$" rules: # Reserved words - statement: "\\b(addrspace|align|allowzero|and|asm|async|await|break|callconv|catch|comptime|const|continue|defer|else|errdefer|error|export|extern|fn|for|if|inline|noalias|noinline|nosuspend|or|orelse|packed|pub|resume|return|linksection|suspend|switch|test|threadlocal|try|unreachable|usingnamespace|var|volatile|while)\\b" # builtin functions - special: "@[a-zA-Z_]+" # Primitive Types - type: "\\b(anyframe|anytype|anyerror|anyopaque|bool|comptime_int|comptime_float|enum|f(16|32|64|80|128)|i(8|16|32|64|128)|isize|noreturn|opaque|struct|type|union|u(8|16|32|64|128)|usize|void)\\b" - type: "\\b(c_u?(short|int|long(long)?)|c_longdouble|c_void)\\b" # Operators - symbol.operator: "[-!|=;%.+^*:&?<>~]" # Parenthesis - symbol.brackets: "[(){}]|\\[|\\]" # Constants - constant: "\\b(null|undefined)\\b" - constant.number: "\\b(0b[01_]+|0o[0-7_]+|[0-9_]+|0x[a-fA-F0-9_]+)\\b" - constant.bool: "\\b(true|false)\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([nrt\\\\'\"]|x[a-fA-F0-9]{2}|u{[a-fA-F0-9]+})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - error: "..+" - constant.specialChar: "\\\\([nrt\\\\'\"]|x[a-fA-F0-9]{2}|u{[a-fA-F0-9]+})" - constant.string: start: "\\\\\\\\" end: "$" skip: "\\\\." rules: - constant.specialChar: "\\\\([nrt\\\\'\"]|x[a-fA-F0-9]{2}|u{[a-fA-F0-9]+})" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/yum.yaml0000664000175000017510000000053315125206537020753 0ustar nileshnileshfiletype: yum detect: filename: "\\.repo$|yum.*\\.conf$" rules: - identifier: "^[[:space:]]*[^=]*=" - constant.specialChar: "^[[:space:]]*\\[.*\\]$" - statement: "\\$(releasever|arch|basearch|uuid|YUM[0-9])" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/yaml.yaml0000664000175000017510000000155315125206537021106 0ustar nileshnileshfiletype: yaml detect: filename: "\\.ya?ml$" header: "%YAML" rules: - type: "(^| )!!(binary|bool|float|int|map|null|omap|seq|set|str) " - constant: "\\b(YES|yes|Y|y|ON|on|TRUE|True|true|NO|no|N|n|OFF|off|FALSE|False|false)\\b" - statement: "(:[[:space:]]|\\[|\\]|:[[:space:]]+[|>]|^[[:space:]]*- )" - identifier: "[[:space:]][\\*&][A-Za-z0-9]+" - type: "[-.\\w]+:" - statement: ":" - special: "(^---|^\\.\\.\\.|^%YAML|^%TAG)" - constant.string: start: "(^| )\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "(^| )'" end: "'" skip: "(\\\\.)|('')" rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/xresources.yaml0000664000175000017510000000060215125206537022340 0ustar nileshnileshfiletype: xresources detect: filename: "X(defaults|resources)$" rules: - special: "^[[:alnum:]]+\\*" - identifier.var: "\\*[[:alnum:]]+\\:" - constant.number: "\\b[0-9]+\\b" - symbol.operator: "[*:=]" - constant.bool: "\\b(true|false)\\b" - comment: "(^|[[:space:]])!([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/xml.yaml0000664000175000017510000000146515125206537020746 0ustar nileshnileshfiletype: xml detect: filename: "\\.(xml|sgml?|rng|svg|plist)$" header: "<\\?xml.*\\?>" rules: - preproc: start: "" rules: [] - comment: start: "" rules: [] - symbol.tag: start: "<\\??" end: "\\??>" rules: - identifier: start: " " end: "=" rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." zyedidia-micro-6a62575/runtime/syntax/vue.yaml0000664000175000017510000000725115125206537020744 0ustar nileshnileshfiletype: vue detect: filename: "\\.vue$" rules: - default: start: "" end: "" limit-group: symbol.tag rules: - error: "<[^!].*?>" - symbol.tag: "(?i)<[/]?(a|a(bbr|ddress|rea|rticle|side|udio)|b|b(ase|d(i|o)|lockquote|r|utton)|ca(nvas|ption)|center|cite|co(de|l|lgroup)|d(ata|atalist|d|el|etails|fn|ialog|l|t)|em|embed|fieldset|fig(caption|ure)|form|iframe|h[1-6]|hr|i|img|in(put|s)|kbd|keygen|label|legend|li|link|ma(in|p|rk)|menu|menuitem|met(a|er)|nav|noscript|o(bject|l|pt(group|ion)|utput)|p|param|picture|pre|progress|q|r(p|t|uby)|s|samp|se(ction|lect)|svg|small|source|span|strong|su(b|p|mmary)|textarea|time|track|u|ul|var|video|wbr)( .*)*?>" - symbol.tag.extended: "(?i)<[/]?(body|div|html|head(er)?|footer|title|table|t(body|d|h(ead)?|r|foot))( .*)*?>" - preproc: "(?i)<[/]?(script|style)( .*)*?>" - special: "&[^;[[:space:]]]*;" - identifier: "(alt|bgcolor|class|height|href|id|label|longdesc|name|on(click|focus|load|mouseover)|placeholder|size|span|src|style|target|type|value|width)=" - symbol: "[:=]" - constant.string: "\"[^\"]*\"" - constant.number: "(?i)#[0-9a-fA-F]{6,6}" - symbol.tag: "<|>" - constant.string.url: "(ftp(s)?|http(s)?|git|chrome)://[^ ]+" - comment: "" #- preproc: "" - comment.block: start: "" rules: [] # Bootstrap - symbol.tag.extended: "(?i)<[/]?(b-alert|b-aspect|b-avatar|b-badge|b-icon|b-breadcrumb|b-button-group|b-button-toolbar|b-button|b-calendar|b-card-text|b-card-input|b-card|b-carousel-slide|b-carousel|b-collapse|b-dropdown|b-dropdown-item|b-dropdown-divider|b-embed|b-form-checkbox-group|b-form-checkbox|b-form-datepicker|b-form-file|b-form-group|b-form-input|b-form-radio|b-form-rating|b-form-select|b-form-spinbutton|b-form-tags|b-form-textarea|b-form|b-form-timepicker|b-img-lazy|b-img|b-input-group|b-jumbotron|b-input|b-container|b-row|b-col|b-link|b-list-group|b-list-group-item|b-media|b-modal|b-nav|b-nav-item|b-nav-item-dropdown|b-nav-text|b-nav-form|b-navbar|b-navbar-brand|b-navbar-toggle|b-navbar-nav|b-overlay|b-pagination|b-pagination-nav|b-popover|b-progress|b-progress-bar|b-sidebar|b-skeleton-wrapper|b-skeleton|b-spinner|b-table|b-table-lite|b-table-simple|b-tabs|b-tab|b-time|b-toast|b-tooltip)\\b" - identifier: "(variant|title|show|shadow|icon|align-h|align-v|label-for|@submit|tag|img-alt|img-src|data-toggle|data-target|aria-controls|aria-expanded|aria-label|aria-disabled|tabindex|:interval|background|img-width|img-height|@sliding-start|@sliding-end|cols|header|@reset)=" - symbol: "[:=]" # Vue - symbol.tag.extended: "(?i)<[/]?(component|transition|transition-group|keep-alive|slot)\\b" - identifier: "(v-text|v-html|v-show|v-if|v-else|v-else-if|v-for|v-on|v-bind|v-model|v-slot|v-pre|v-cloak|v-once|key|ref|is|@click)=" - symbol: "[:=]" # Vue-router - symbol.tag.extended: "(?i)<[/]?(router-link|router-view)\\b" - identifier: "(to|v-slot)=" - symbol: "[:=]" - default: start: "" limit-group: symbol.tag rules: - include: "javascript" - default: start: "" end: "" rules: - include: "typescript" - default: start: "" end: "" limit-group: symbol.tag rules: - include: "css" zyedidia-micro-6a62575/runtime/syntax/vi.yaml0000664000175000017510000000137615125206537020565 0ustar nileshnileshfiletype: vi detect: filename: "(^|/|\\.)(ex|vim)rc$|\\.vim" rules: - identifier: "[A-Za-z_][A-Za-z0-9_]*[(]+[A-Za-z0-9_:.,\\s]*[)]+" - special: "[()]+" - statement: "\\b([nvxsoilc]?(nore|un)?map|[nvlx]n|[ico]?no|[cilovx][um]|s?unm)\\b" - statement: "\\b(snor|nun|nm|set|if|endif|let|unlet|source)\\b" - statement: "[!&=?]" - constant.number: "\\b[0-9]+\\b" - comment: start: "(^\"|[ \t]+\" |[ \t]+\"$)" end: "$" rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." zyedidia-micro-6a62575/runtime/syntax/vhdl.yaml0000664000175000017510000000454715125206537021107 0ustar nileshnileshfiletype: vhdl detect: filename: "\\.vhdl?$" rules: - type: "(?i)\\b(string|integer|natural|positive|(un)?signed|std_u?logic(_vector)?|bit(_vector)?|boolean|u?x01z?|array|range)\\b" - identifier: "(?i)library[[:space:]]+[a-zA-Z_0-9]+" - identifier: "(?i)use[[:space:]]+[a-zA-Z_0-9\\.]+" - identifier: "(?i)component[[:space:]]+[a-zA-Z_0-9]+" - identifier: "(?i)(architecture|configuration)[[:space:]]+[a-zA-Z_0-9]+[[:space:]]+of[[:space:]]+[a-zA-Z_0-9]+" - identifier: "(?i)(entity|package)[[:space:]]+[a-zA-Z_0-9]+[[:space:]]+is" - identifier: "(?i)end[[:space:]]+((architecture|entity|component|process|package|generate)[[:space:]]+)?[a-zA-Z_0-9]+" - statement: "(?i)\\b(abs|access|after|alias|all|and|architecture|assert|attribute)\\b" - statement: "(?i)\\b(begin|block|body|buffer|bus|case|component|configuration|constant)\\b" - statement: "(?i)\\b(disconnect|downto|else|elsif|end|entity|exit)\\b" - statement: "(?i)\\b(file|for|function|generate|generic|guarded)\\b" - statement: "(?i)\\b(if|impure|in|inertial|inout|is)\\b" - statement: "(?i)\\b(label|library|linkage|literal|loop|map|mod)\\b" - statement: "(?i)\\b(nand|new|next|nor|not|null|of|on|open|or|others|out)\\b" - statement: "(?i)\\b(package|port|postponed|procedure|process|pure)\\b" - statement: "(?i)\\b(range|record|register|reject|rem|report|return|rol|ror)\\b" - statement: "(?i)\\b(select|severity|shared|signal|sla|sll|sra|srl|subtype)\\b" - statement: "(?i)\\b(then|to|transport|type|unaffected|units|until|use)\\b" - statement: "(?i)\\b(variable|wait|when|while|with|xnor|xor)\\b" - statement: "(?i)'(base|left|right|high|low|pos|val|succ|pred|leftof|rightof|image|(last_)?value)" - statement: "(?i)'((reverse_)?range|length|ascending|event|stable)" - statement: "(?i)'(simple|path|instance)_name" - statement: "(?i)\\b(std_match|(rising|falling)_edge|is_x)\\b" - statement: "(?i)\\bto_(unsigned|signed|integer|u?x01z?|stdu?logic(vector)?)\\b" - symbol.operator: "(\\+|-|\\*|/|&|<|>|=|\\.|:)" - constant.number: "(?i)'([0-1]|u|x|z|w|l|h|-)'|[box]?\"([0-1a-fA-F]|u|x|z|w|l|h|-)+\"" - constant.number: "(?i)\\b[0-9\\._]+(e[\\-]?[0-9]+)?( ?[fpnum]?s)?\\b" - constant.bool: "(?i)\\b(true|false)\\b" - constant: "(?i)\\b(note|warning|error|failure)\\b" - constant.string: "\"[^\"]*\"" - comment: "--.*" zyedidia-micro-6a62575/runtime/syntax/verilog.yaml0000664000175000017510000000570115125206537021612 0ustar nileshnileshfiletype: verilog detect: filename: "\\.(v|vh|sv|svh)$" rules: - preproc: "\\b(module|package|program|endmodule|endpackage|endprogram)\\b" - type.keyword: "\\b(task|interface|class|endtask|endinterface|endclass)\\b" # builtin functions like $display - special: "\\$[0-9A-Za-z_]+" # Verilog keywords - statement: "\\b(always|and|assign|automatic|begin|buf|bufif0|bufif1|case|casex|casez|cell|cmos|config)\\b" - statement: "\\b(deassign|default|defparam|design|disable|edge|else|end|endcase|endconfig|endfunction|endgenerate)\\b" - statement: "\\b(endprimitive|endspecify|endtable|event|for|force|forever|fork|function|generate)\\b" - statement: "\\b(genvar|highz0|highz1|if|iff|ifnone|incdir|include|initial|input|instance|join)\\b" - statement: "\\b(large|liblist|library|localparam|macromodule|medium|nand|negedge|nmos|nor|noshowcancelled)\\b" - statement: "\\b(not|notif0|notif1|null|or|output|parameter|pmos|posedge|primitive|pull0|pull1|pulldown|pullup)\\b" - statement: "\\b(pulsestyle_onevent|pulsestyle_ondetect|rcmos|realtime|reg|release|repeat|rnmos|rpmos|rtran)\\b" - statement: "\\b(rtranif0|rtranif1|scalared|showcancelled|small|specify|specparam|strong0|strong1|supply0)\\b" - statement: "\\b(supply1|table|time|tran|tranif0|tranif1|tri0|tri1|triand|trior|trireg|use|uwire)\\b" - statement: "\\b(vectored|wait|wand|weak0|weak1|while|wor|xnor|xor)\\b" # SystemVerilog keywords - statement: "\\b(alias|always_comb|always_ff|always_latch|assert|assume|before|bind|bins|binsof|break)\\b" - statement: "\\b(chandle|clocking|const|constraint|context|continue|cover|covergroup|coverpoint|cross|dist|do)\\b" - statement: "\\b(endclocking|endgroup|endproperty|endsequence|enum)\\b" - statement: "\\b(expect|export|extends|extern|final|first_match|foreach|forkjoin|ignore_bins|illegal_bins|import)\\b" - statement: "\\b(inside|intersect|join_any|join_none|local|longint|matches|modport|new)\\b" - statement: "\\b(packed|priority|property|protected|pure|rand|randc|randcase|randsequence|ref|return)\\b" - statement: "\\b(sequence|solve|static|struct|super|tagged|this|throughout|timeprecision)\\b" - statement: "\\b(timeunit|type|typedef|union|unique|virtual|wait_order|wildcard|with|within)\\b" # types - type.keyword: "\\b(int|integer|logic|wire|tri|unsigned|signed|inout|var|shortint|shortreal|real|void|string|bit|byte)\\b" # constants - constant.number: "\\b[0-9]+\\b" - constant.number: "\\b'[su]?[dboh][0-9xzXZa-fA-F]+\\b" # .asdf(...) argument syntax - special: "\\.((\\*)|([A-Za-z][A-Za-z0-9_]*))" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/vala.yaml0000664000175000017510000000170715125206537021070 0ustar nileshnileshfiletype: vala detect: filename: "\\.vala$" rules: - type: "\\b(float|double|bool|u?char|u?int(8|16|32|64)?|u?short|u?long|void|s?size_t|unichar)\\b" - identifier.class: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[()]" - statement: "\\b(for|if|while|do|else|case|default|switch|try|throw|catch)\\b" - statement: "\\b(inline|typedef|struct|enum|union|extern|static|const)\\b" - statement: "\\b(operator|new|delete|return|null)\\b" - statement: "\\b(class|override|private|public|signal|this|weak)\\b" - special: "\\b(goto|break|continue)\\b" - constant.bool: "\\b(true|false)\\b" - constant.number: "\\b([0-9]+)\\b" - symbol.operator: "[\\-+/*=<>?:!~%&|]|->" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - comment: "(^|[[:space:]])//.*" - comment: start: "/\\*" end: "\\*/" rules: [] - todo: "TODO:?" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/v.yaml0000664000175000017510000000510715125206537020410 0ustar nileshnileshfiletype: v detect: rules: # Conditionals and control flow - preproc: "\\b(module|import)\\b" - statement: "\\b(if|else|for|match|select|defer|or|unsafe)\\b" - statement: "\\b(break|continue|goto|return)\\b" - type.keyword: "\\b(assert|const|enum|fn|struct|interface|type)\\b" - type.keyword: "\\b(pub|mut|__global)\\b" - preproc: "\\$\\b(if|else)\\b" - identifier.os: "\\b(mac|macos|linux|windows|freebsd|openbsd|netbsd|dragonfly|android|solaris|haiku)\\b" - identifier.compiler: "\\b(gcc|tinyc|clang|mingw|msvc|cplusplus)\\b" - identifier.platform: "\\b(amd64|aarch64|x64|x32|little_endian|big_endian)\\b" - identifier.other: "\\b(debug|test|js|glibc|prealloc|no_bounds_checking)\\b" - identifier.class: "\\b([A-Z][A-Za-z0-9_]*)\\b" - identifier.function: "\\b([a-z_]+\\()" - symbol.operator: "\\b(i[ns])\\b|[-+/*<>!=~*%&:|,.?]" - symbol.attribute: start: "^\\[" end: "\\]$" rules: - default: ".*" - symbol: "\\b(deprecated|direct_array_access|if|inline|live|ref_only|typedef|windows_stdcall)\\b" # Types - type: "\\b(byte|u(16|32|64|128)|i(nt|8|16|64|128)|f(32|64))\\b" - type: "\\b(bool|cha[nr]|map|rune|string)\\b" - type: "\\b(any(_int|_float)?|size_t|(uint|byte|char|void)ptr)\\b" - constant.bool: "\\b(true|false)\\b" - constant.none: "\\b(none)\\b" # Brackets - symbol.brackets: "(\\{|\\})" - symbol.brackets: "(\\(|\\))" - symbol.brackets: "(\\[|\\])" # Numbers and strings - constant.number: "\\b(0b[01_]+)\\b" - constant.number: "\\b(0o[0-7_]+)\\b" - constant.number: "\\b(0x[0-9a-fA-F_]+)\\b" - constant.number: "\\b([0-9_]+)\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abefnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abefnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - constant.string: start: "`" end: "`" rules: [] - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/typescript.yaml0000664000175000017510000000357115125206537022354 0ustar nileshnileshfiletype: typescript detect: filename: "\\.tsx?$" rules: - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b" - constant.number: "\\b[-+]?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?" - constant.number: "\\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?" - identifier: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]" - statement: "\\b(abstract|as|async|await|break|case|catch|class|const|constructor|continue)\\b" - statement: "\\b(debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from)\\b" - statement: "\\b(function|get|if|implements|import|in|instanceof|interface|is|let|module|namespace)\\b" - statement: "\\b(new|of|package|private|protected|public|require|return|set|static|super|switch)\\b" - statement: "\\b(this|throw|try|type|typeof|var|void|while|with|yield)\\b" - constant: "\\b(false|true|null|undefined|NaN)\\b" - type: "\\b(Array|Boolean|Date|Enumerator|Error|Function|Math)\\b" - type: "\\b(Number|Object|RegExp|String|Symbol)\\b" - type: "\\b(any|unknown|boolean|never|number|string|symbol)\\b" - statement: "[-+/*=<>!~%?:&|]" - constant: "/[^*]([^/]|(\\\\/))*[^\\\\]/[gim]*" - constant: "\\\\[0-7][0-7]?[0-7]?|\\\\x[0-9a-fA-F]+|\\\\[bfnrt'\"\\?\\\\]" - comment: start: "//" end: "$" rules: [] - comment: start: "/\\*" end: "\\*/" rules: - todo: "TODO:?" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "`" end: "`" rules: - constant.specialChar: "\\\\." - identifier: "\\x24\\{.*?\\}" zyedidia-micro-6a62575/runtime/syntax/twig.yaml0000664000175000017510000000477515125206537021127 0ustar nileshnileshfiletype: twig detect: filename: "\\.twig$" rules: - include: "html" - symbol.tag: start: "\\{\\{[[:space:]]" end: "[[:space:]]\\}\\}" rules: - identifier: "\\b(abs|batch|capitalize|convert|encoding|date(_modify)?|default|escape|first|format|join|json_encode|keys|last|length|lower|merge|nl2br|number_format|raw|replace|reverse|round|slice|sort|split|striptags|title|trim|upper|url_encode)\\b" - identifier.class: "\\b(attribute|block|constant|cycle|date|dump|include|max|min|parent|random|range|source|template_from_string)\\b" - type.keyword: "\\b(and|as|constant|defined|divisibleby|empty|even|false|in|is|iterable|not|null|odd|or|same(as)?|true|with)\\b" - symbol.operator: "[.:;,+*?|=!\\%]|<|>|/|-|&" - symbol.brackets: "[(){}]|\\[|\\]" - constant.number: "\\b[0-9]+\\b|\\b0x[0-9A-Fa-f]+\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\" rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\" rules: - constant.specialChar: "\\\\." - symbol.tag: start: "\\{%[[:space:]]" end: "[[:space:]]%\\}" rules: - identifier: "\\b(abs|batch|capitalize|convert|encoding|date(_modify)?|default|escape|first|format|join|json_encode|keys|last|length|lower|merge|nl2br|number_format|raw|replace|reverse|round|slice|sort|split|striptags|title|trim|upper|url_encode)\\b" - identifier.class: "\\b(attribute|block|constant|cycle|date|dump|include|max|min|parent|random|range|source|template_from_string)\\b" - type.keyword: "\\b(and|as|constant|defined|divisibleby|empty|even|false|in|is|iterable|not|null|odd|or|same(as)?|true|with)\\b" - symbol.operator: "[.:;,+*?|=!\\%]|<|>|/|-|&" - symbol.brackets: "[(){}]|\\[|\\]" - constant.number: "\\b[0-9]+\\b|\\b0x[0-9A-Fa-f]+\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\" rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\" rules: - constant.specialChar: "\\\\." - comment: start: "\\{#" end: "#\\}" rules: [] zyedidia-micro-6a62575/runtime/syntax/toml.yaml0000664000175000017510000000330615125206537021115 0ustar nileshnileshfiletype: toml detect: filename: "\\.toml" rules: # Punctuation - symbol: '[=,\.]' - symbol.brackets: '[{\[\]}]' # Strings - constant.string: start: '"""' end: '\"{3,5}' skip: '\\.' rules: - constant.specialChar: '\\u[[:xdigit:]]{4}' - constant.specialChar: '\\U[[:xdigit:]]{8}' - constant.specialChar: '\\[btnfr"\\]' - constant.string: start: '"' end: '"' skip: '\\.' rules: - constant.specialChar: '\\u[[:xdigit:]]{4}' - constant.specialChar: '\\U[[:xdigit:]]{8}' - constant.specialChar: '\\[btnfr"\\]' - constant.string: start: "'''" end: "'{3,5}" rules: [] - constant.string: start: "'" end: "'" rules: [] # Integer - constant.number: '[+-]?(\d+_)*\d+\b' - constant.number: '(0x([[:xdigit:]]+_)*[[:xdigit:]]+|0o([0-7]_)*[0-7]+|0b([01]+_)*[01]+)' # Float - constant.number: '[+-]?(\d+_)*\d+\.(\d+_)*\d+' - constant.number: '[+-]?(\d+_)*\d+(\.(\d+_)*\d+)?[Ee][+-]?(\d+_)*\d+' - constant.number: '(\+|-)(inf|nan)' # Bare key, keys starting with a digit or dash are ambiguous with numbers and are skipped - identifier: '\b[A-Za-z_][A-Za-z0-9_-]*\b' # Boolean and inf, nan without sign - constant.bool.true: '\btrue\b' - constant.bool.false: '\bfalse\b' - constant.number: '\b(inf|nan)\b' # Date and Time - constant: '\d+-\d{2}-\d{2}([T ]\d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}:\d{2}|Z)?)?' - constant: '\d{2}:\d{2}:\d{2}(\.\d+)?' # Comments - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/tex.yaml0000664000175000017510000000142315125206537020740 0ustar nileshnileshfiletype: tex detect: filename: "\\.tex$|\\.bib$|\\.cls$" rules: # colorize the identifiers of {} and [] - identifier: start: "\\{" end: "\\}" rules: [] - identifier: start: "\\[" end: "\\]" rules: [] # numbers - constant.number: "\\b[0-9]+(\\.[0-9]+)?([[:space:]](pt|mm|cm|in|ex|em|bp|pc|dd|cc|nd|nc|sp))?\\b" # let brackets have the default color again - default: "[{}\\[\\]]" - special: "[&\\\\]" # macros - statement: "\\\\@?[a-zA-Z_]+" - statement: "\\\\%" # comments - comment: start: "[^\\\\]%|^%" end: "$" rules: [] - comment: start: "\\\\begin\\{comment\\}" end: "\\\\end\\{comment\\}" rules: [] zyedidia-micro-6a62575/runtime/syntax/terraform.yaml0000664000175000017510000001003715125206537022142 0ustar nileshnilesh# # This syntax definition is based on the Terraform guide: # https://www.terraform.io/docs/configuration/index.html # # Formatting is loosely based on Sublime's and VSCode's syntax highlighting for Terraform: # https://github.com/totoroot/Terraform.tmLanguage/blob/master/Terraform.sublime-syntax # https://github.com/hashicorp/vscode-terraform/blob/main/syntaxes/terraform.tmGrammar.json # filetype: terraform detect: # File Extensions: # # - ".tf": the standard file extension # https://www.terraform.io/docs/configuration/index.html#code-organization # # - ".hcl": non-terraform tools often use this HCL syntax, i.e. Vault # https://www.vaultproject.io/docs/configuration/ filename: "\\.tf$|\\.hcl$" rules: # Named Values # # https://www.terraform.io/docs/language/expressions/references.html - identifier: "\\b(var|local|module|data|path|terraform)\\b" # Block types # # resource: https://www.terraform.io/docs/language/resources/syntax.html # provider: https://www.terraform.io/docs/language/providers/configuration.html # variable: https://www.terraform.io/docs/language/values/variables.html # output: https://www.terraform.io/docs/language/values/outputs.html # locals: https://www.terraform.io/docs/language/values/locals.html # module: https://www.terraform.io/docs/language/modules/syntax.html # data: https://www.terraform.io/docs/language/data-sources/index.html # terraform: https://www.terraform.io/docs/language/settings/index.html#terraform-block-syntax - special: "\\b(resource|provider|variable|output|locals|module|terraform)\\b" # Built-In type keywords # # https://www.terraform.io/docs/language/expressions/type-constraints.html#primitive-types # https://www.terraform.io/docs/language/expressions/type-constraints.html#dynamic-types-the-quot-any-quot-constraint - type.keyword: "\\b(any|string|number|bool)\\b" # Built-In Functions # # https://www.terraform.io/docs/language/functions/index.html - statement: "\\b(abs|ceil|floor|log|max|min|parseint|pow|signum|chomp|format|formatlist|indent|join|lower|regex|regexall|replace|split|strrev|substr|title|trim|trimprefix|trimsuffix|trimspace|upper|alltrue|anytrue|chunklist|coalesce|coalescelist|compact|concat|contains|distinct|element|flatten|index|keys|length|list|lookup|map|matchkeys|merge|one|range|reverse|setintersection|setproduct|setsubtract|setunion|slice|sort|sum|transpose|values|zipmap|base64decode|base64encode|base64gzip|csvdecode|jsondecode|jsonencode|textdecodebase64|textencodebase64|urlencode|yamldecode|yamlencode|abspath|dirname|pathexpand|basename|file|fileexists|fileset|filebase64|templatefile|formatdate|timeadd|timestamp|base64sha256|base64sha512|bcrypt|filebase64sha256|filebase64sha512|filemd5|filesha1|filesha256|filesha512|md5|rsadecrypt|sha1|sha256|sha512|uuid|uuidv5|cidrhost|cidrnetmask|cidrsubnet|cidrsubnets|can|defaults|nonsensitive|sensitive|tobool|tolist|tomap|tonumber|toset|tostring|try)\\b" - symbol.operator: "([~^.:;,+*|=!\\%@]|<|>|/|-|&)" - symbol.brackets: "([(){}]|\\[|\\])" - constant.number: "\\b([0-9]+|0x[0-9a-fA-F]*)\\b|'.'" - constant.bool: "\\b(true|false|null)\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - constant.string: start: "''" end: "''" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - comment: start: "#|//" end: "$\\n?" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/tcl.yaml0000664000175000017510000000426715125206537020733 0ustar nileshnileshfiletype: tcl detect: filename: "\\.tcl$" header: "^#!.*/(env +)?tclsh( |$)" rules: - statement: "\\b(after|append|array|auto_execok|auto_import|auto_load|auto_load_index|auto_qualify|binary|break|case|catch|cd|clock|close|concat|continue|else|elseif|encoding|eof|error|eval|exec|exit|expr|fblocked|fconfigure|fcopy|file|fileevent|flush|for|foreach|format|gets|glob|global|history|if|incr|info|interp|join|lappend|lindex|linsert|list|llength|load|lrange|lreplace|lsearch|lset|lsort|namespace|open|package|pid|puts|pwd|read|regexp|regsub|rename|return|scan|seek|set|socket|source|split|string|subst|switch|tclLog|tell|time|trace|unknown|unset|update|uplevel|upvar|variable|vwait|while)\\b" - statement: "\\b(array anymore|array donesearch|array exists|array get|array names|array nextelement|array set|array size|array startsearch|array statistics|array unset)\\b" - statement: "\\b(string bytelength|string compare|string equal|string first|string index|string is|string last|string length|string map|string match|string range|string repeat|string replace|string to|string tolower|string totitle|string toupper|string trim|string trimleft|string trimright|string will|string wordend|string wordstart)\\b" - statement: "\\b(alarm|auto_load_pkg|bsearch|catclose|catgets|catopen|ccollate|cconcat|cequal|chgrp|chmod|chown|chroot|cindex|clength|cmdtrace|commandloop|crange|csubstr|ctoken|ctype|dup|echo|execl|fcntl|flock|fork|fstat|ftruncate|funlock|host_info|id|infox|keyldel|keylget|keylkeys|keylset|kill|lassign|lcontain|lempty|lgets|link|lmatch|loadlibindex|loop|lvarcat|lvarpop|lvarpush|max|min|nice|pipe|profile|random|readdir|replicate|scancontext|scanfile|scanmatch|select|server_accept|server_create|signal|sleep|sync|system|tclx_findinit|tclx_fork|tclx_load_tndxs|tclx_sleep|tclx_system|tclx_wait|times|translit|try_eval|umask|wait)\\b" - identifier.class: "proc[[:space:]]|(\\{|\\})" - symbol.operator: "(\\(|\\)|\\;|`|\\\\|\\$|<|>|!|=|&|\\|)" - constant.number: "\\b[0-9]+(\\.[0-9]+)?\\b" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - identifier.var: "\\$\\{?[0-9A-Z_!@#$*?-]+\\}?" - comment: "(^|;)[[:space:]]*#.*" - indent-char.whitespace: "[[:space:]]+$" zyedidia-micro-6a62575/runtime/syntax/systemd.yaml0000664000175000017510000001211115125206537021624 0ustar nileshnileshfiletype: systemd detect: filename: "\\.(service|socket|timer)$" header: "^\\[Unit\\]$" rules: - statement: "^(Accept|After|Alias|AllowIsolate|Also|ANSI_COLOR|_AUDIT_LOGINUID|_AUDIT_SESSION|Backlog|Before|BindIPv6Only|BindsTo|BindToDevice|BlockIOReadBandwidth|BlockIOWeight|BlockIOWriteBandwidth|_BOOT_ID|Broadcast|BUG_REPORT_URL|BusName|Capabilities|CapabilityBoundingSet|CHASSIS|cipher|class|_CMDLINE|CODE_FILE|CODE_FUNC|CODE_LINE|_COMM|Compress|ConditionACPower|ConditionCapability|ConditionDirectoryNotEmpty|ConditionFileIsExecutable|ConditionFileNotEmpty|ConditionHost|ConditionKernelCommandLine|ConditionNull|ConditionPathExists|ConditionPathExistsGlob|ConditionPathIsDirectory|ConditionPathIsMountPoint|ConditionPathIsReadWrite|ConditionPathIsSymbolicLink|ConditionSecurity|ConditionVirtualization|Conflicts|ControlGroup|ControlGroupAttribute|ControlGroupModify|ControlGroupPersistent|controllers|Controllers|CPE_NAME|CPUAffinity|CPUSchedulingPolicy|CPUSchedulingPriority|CPUSchedulingResetOnFork|CPUShares|CrashChVT|CrashShell|__CURSOR|debug|DefaultControllers|DefaultDependencies|DefaultLimitAS|DefaultLimitCORE|DefaultLimitCPU|DefaultLimitDATA|DefaultLimitFSIZE|DefaultLimitLOCKS|DefaultLimitMEMLOCK|DefaultLimitMSGQUEUE|DefaultLimitNICE|DefaultLimitNOFILE|DefaultLimitNPROC|DefaultLimitRSS|DefaultLimitRTPRIO|DefaultLimitRTTIME|DefaultLimitSIGPENDING|DefaultLimitSTACK|DefaultStandardError|DefaultStandardOutput|Description|DeviceAllow|DeviceDeny|DirectoryMode|DirectoryNotEmpty|Documentation|DumpCore|entropy|Environment|EnvironmentFile|ERRNO|event_timeout|_EXE|ExecReload|ExecStart|ExecStartPost|ExecStartPre|ExecStop|ExecStopPost|ExecStopPre|filter|FONT|FONT_MAP|FONT_UNIMAP|ForwardToConsole|ForwardToKMsg|ForwardToSyslog|FreeBind|freq|FsckPassNo|fstab|_GID|Group|GuessMainPID|HandleHibernateKey|HandleLidSwitch|HandlePowerKey|HandleSuspendKey|hash|HibernateKeyIgnoreInhibited|HOME_URL|_HOSTNAME|ICON_NAME|ID|IdleAction|IdleActionSec|ID_LIKE|ID_MODEL|ID_MODEL_FROM_DATABASE|IgnoreOnIsolate|IgnoreOnSnapshot|IgnoreSIGPIPE|InaccessibleDirectories|InhibitDelayMaxSec|init|IOSchedulingClass|IOSchedulingPriority|IPTOS|IPTTL|JobTimeoutSec|JoinControllers|KeepAlive|KEYMAP|KEYMAP_TOGGLE|KillExcludeUsers|KillMode|KillOnlyUsers|KillSignal|KillUserProcesses|LidSwitchIgnoreInhibited|LimitAS|LimitCORE|LimitCPU|LimitDATA|LimitFSIZE|LimitLOCKS|LimitMEMLOCK|LimitMSGQUEUE|LimitNICE|LimitNOFILE|LimitNPROC|LimitRSS|LimitRTPRIO|LimitRTTIME|LimitSIGPENDING|LimitSTACK|link_priority|valueListenDatagram|ListenFIFO|ListenMessageQueue|ListenNetlink|ListenSequentialPacket|ListenSpecial|ListenStream|LogColor|LogLevel|LogLocation|LogTarget|luks|_MACHINE_ID|MakeDirectory|Mark|MaxConnections|MaxFileSec|MaxLevelConsole|MaxLevelKMsg|MaxLevelStore|MaxLevelSyslog|MaxRetentionSec|MemoryLimit|MemorySoftLimit|MESSAGE|MESSAGE_ID|MessageQueueMaxMessages|MessageQueueMessageSize|__MONOTONIC_TIMESTAMP|MountFlags|NAME|NAutoVTs|Nice|NonBlocking|NoNewPrivileges|NotifyAccess|OnActiveSec|OnBootSec|OnCalendar|OnFailure|OnFailureIsolate|OnStartupSec|OnUnitActiveSec|OnUnitInactiveSec|OOMScoreAdjust|Options|output|PAMName|PartOf|PassCredentials|PassSecurity|PathChanged|PathExists|PathExistsGlob|PathModified|PermissionsStartOnly|_PID|PIDFile|PipeSize|PowerKeyIgnoreInhibited|PRETTY_HOSTNAME|PRETTY_NAME|Priority|PRIORITY|PrivateNetwork|PrivateTmp|PropagatesReloadTo|pss|RateLimitBurst|RateLimitInterval|ReadOnlyDirectories|ReadWriteDirectories|__REALTIME_TIMESTAMP|ReceiveBuffer|RefuseManualStart|RefuseManualStop|rel|ReloadPropagatedFrom|RemainAfterExit|RequiredBy|Requires|RequiresMountsFor|RequiresOverridable|Requisite|RequisiteOverridable|ReserveVT|ResetControllers|Restart|RestartPreventExitStatus|RestartSec|RootDirectory|RootDirectoryStartOnly|RuntimeKeepFree|RuntimeMaxFileSize|RuntimeMaxUse|RuntimeWatchdogSec|samples|scale_x|scale_y|Seal|SecureBits|_SELINUX_CONTEXT|SendBuffer|SendSIGKILL|Service|ShowStatus|ShutdownWatchdogSec|size|SmackLabel|SmackLabelIPIn|SmackLabelIPOut|SocketMode|Sockets|SourcePath|_SOURCE_REALTIME_TIMESTAMP|SplitMode|StandardError|StandardInput|StandardOutput|StartLimitAction|StartLimitBurst|StartLimitInterval|static_node|StopWhenUnneeded|Storage|string_escape|none|replaceSuccessExitStatus|SupplementaryGroups|SUPPORT_URL|SuspendKeyIgnoreInhibited|SyslogFacility|SYSLOG_FACILITY|SyslogIdentifier|SYSLOG_IDENTIFIER|SyslogLevel|SyslogLevelPrefix|SYSLOG_PID|SystemCallFilter|SYSTEMD_ALIAS|_SYSTEMD_CGROUP|_SYSTEMD_OWNER_UID|SYSTEMD_READY|_SYSTEMD_SESSION|_SYSTEMD_UNIT|_SYSTEMD_USER_UNIT|SYSTEMD_WANTS|SystemKeepFree|SystemMaxFileSize|SystemMaxUse|SysVStartPriority|TCPCongestion|TCPWrapName|timeout|TimeoutSec|TimeoutStartSec|TimeoutStopSec|TimerSlackNSec|Transparent|_TRANSPORT|tries|TTYPath|TTYReset|TTYVHangup|TTYVTDisallocate|Type|_UID|UMask|Unit|User|UtmpIdentifier|VERSION|VERSION_ID|WantedBy|Wants|WatchdogSec|What|Where|WorkingDirectory)=" - preproc: "^\\.include\\>" - symbol: "=" - special: "^\\[(Unit|Install|Service|Socket|Timer)\\]" - identifier.class: "\\$MAINPID" - constant.bool: "\\b(true|false)\\b" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/syntax_converter.go0000664000175000017510000001150415125206537023221 0ustar nileshnilesh//go:build ignore package main import ( "fmt" "os" "regexp" "strings" ) type SingleRule struct { color string regex string } type MultiRule struct { color string start string end string } // JoinRule takes a syntax rule (which can be multiple regular expressions) // and joins it into one regular expression by ORing everything together func JoinRule(rule string) string { split := strings.Split(rule, `" "`) joined := strings.Join(split, "|") return joined } func parseFile(text, filename string) (filetype, syntax, header string, rules []any) { lines := strings.Split(text, "\n") // Regex for parsing syntax statements syntaxParser := regexp.MustCompile(`syntax "(.*?)"\s+"(.*)"+`) // Regex for parsing header statements headerParser := regexp.MustCompile(`header "(.*)"`) // Regex for parsing standard syntax rules ruleParser := regexp.MustCompile(`color (.*?)\s+(?:\((.+?)?\)\s+)?"(.*)"`) // Regex for parsing syntax rules with start="..." end="..." ruleStartEndParser := regexp.MustCompile(`color (.*?)\s+(?:\((.+?)?\)\s+)?start="(.*)"\s+end="(.*)"`) for lineNum, line := range lines { line = strings.TrimSpace(line) if line == "" { continue } if strings.HasPrefix(line, "#") { continue } if strings.HasPrefix(line, "syntax") { syntaxMatches := syntaxParser.FindSubmatch([]byte(line)) if len(syntaxMatches) == 3 { filetype = string(syntaxMatches[1]) syntax = JoinRule(string(syntaxMatches[2])) } else { fmt.Println(filename, lineNum, "Syntax statement is not valid: "+line) continue } } if strings.HasPrefix(line, "header") { // Header statement headerMatches := headerParser.FindSubmatch([]byte(line)) if len(headerMatches) == 2 { header = JoinRule(string(headerMatches[1])) } else { fmt.Println(filename, lineNum, "Header statement is not valid: "+line) continue } } // Syntax rule, but it could be standard or start-end if ruleParser.MatchString(line) { // Standard syntax rule // Parse the line submatch := ruleParser.FindSubmatch([]byte(line)) var color string var regexStr string var flags string if len(submatch) == 4 { // If len is 4 then the user specified some additional flags to use color = string(submatch[1]) flags = string(submatch[2]) if flags != "" { regexStr = "(?" + flags + ")" + JoinRule(string(submatch[3])) } else { regexStr = JoinRule(string(submatch[3])) } } else if len(submatch) == 3 { // If len is 3, no additional flags were given color = string(submatch[1]) regexStr = JoinRule(string(submatch[2])) } else { // If len is not 3 or 4 there is a problem fmt.Println(filename, lineNum, "Invalid statement: "+line) continue } rules = append(rules, SingleRule{color, regexStr}) } else if ruleStartEndParser.MatchString(line) { // Start-end syntax rule submatch := ruleStartEndParser.FindSubmatch([]byte(line)) var color string var start string var end string // Use m and s flags by default if len(submatch) == 5 { // If len is 5 the user provided some additional flags color = string(submatch[1]) start = string(submatch[3]) end = string(submatch[4]) } else if len(submatch) == 4 { // If len is 4 the user did not provide additional flags color = string(submatch[1]) start = string(submatch[2]) end = string(submatch[3]) } else { // If len is not 4 or 5 there is a problem fmt.Println(filename, lineNum, "Invalid statement: "+line) continue } // rules[color] = "(?" + flags + ")" + "(" + start + ").*?(" + end + ")" rules = append(rules, MultiRule{color, start, end}) } } return } func generateFile(filetype, syntax, header string, rules []any) string { output := "" output += fmt.Sprintf("filetype: %s\n\n", filetype) output += fmt.Sprintf("detect: \n filename: \"%s\"\n", strings.Replace(strings.Replace(syntax, "\\", "\\\\", -1), "\"", "\\\"", -1)) if header != "" { output += fmt.Sprintf(" signature: \"%s\"\n", strings.Replace(strings.Replace(header, "\\", "\\\\", -1), "\"", "\\\"", -1)) } output += "\nrules:\n" for _, r := range rules { if rule, ok := r.(SingleRule); ok { output += fmt.Sprintf(" - %s: \"%s\"\n", rule.color, strings.Replace(strings.Replace(rule.regex, "\\", "\\\\", -1), "\"", "\\\"", -1)) } else if rule, ok := r.(MultiRule); ok { output += fmt.Sprintf(" - %s:\n", rule.color) output += fmt.Sprintf(" start: \"%s\"\n", strings.Replace(strings.Replace(rule.start, "\\", "\\\\", -1), "\"", "\\\"", -1)) output += fmt.Sprintf(" end: \"%s\"\n", strings.Replace(strings.Replace(rule.end, "\\", "\\\\", -1), "\"", "\\\"", -1)) } } return output } func main() { if len(os.Args) < 2 { fmt.Println("no args") return } data, _ := os.ReadFile(os.Args[1]) fmt.Print(generateFile(parseFile(string(data), os.Args[1]))) } zyedidia-micro-6a62575/runtime/syntax/swift.yaml0000664000175000017510000001052515125206537021277 0ustar nileshnileshfiletype: swift detect: filename: "\\.swift$" header: "^#!.*bin/(env +)?swift( |$)" rules: # Patterns - type: \b(_)\b # Operators - symbol.operator: ([.:;,+*|=!?\\%]|<|>|/|-|&) # Declaration Keywords - statement.declaration: \b(associatedtype|class|deinit|enum|extension|fileprivate|func|import|init)\b - statement.declaration: \b(inout|internal|let|open|operator|private|protocol|public|static|struct|subscript|typealias|var)\b # Statements Keywords - statement: \b(break|case|continue|default|defer|do|else|fallthrough|for|guard)\b - statement: \b(if|inif|repeat|return|switch|where|while)\b # keyword.reserved - statement.reserved: \b(associativity|convenience|dynamic|didSet|final|get|infix|indirect|lazy|left|mutating)\b - statement.reserved: \b(none|nonmutating|override|postfix|precedence|prefix|Protocol|required)\b - statement.reserved: \b(right|set|Type|unowned|weak|willSet)\b # Expression and types - type: \b(as|Any|catch|is|rethrows|super|self|throw|throws|try)\b - statement.built_in: \b(abs|advance|alignof|alignofValue|anyGenerator|assert|assertionFailure|bridgeFromObjectiveC)\b - statement.built_in: \b(bridgeFromObjectiveCUnconditional|bridgeToObjectiveC|bridgeToObjectiveCUnconditional|contains)\b - statement.built_in: \b(count|countElements|countLeadingZeros|debugPrint|debugPrintln|distance|dropFirst|dropLast|dump|encodeBitsAsWords)\b - statement.built_in: \b(enumerate|equal|fatalError|filter|find|getBridgedObjectiveCType|getVaList|indices|insertionSort)\b - statement.built_in: \b(isBridgedToObjectiveC|isBridgedVerbatimToObjectiveC|isUniquelyReferenced|isUniquelyReferencedNonObjC)\b - statement.built_in: \b(join|lexicographicalCompare|map|max|maxElement|min|minElement|numericCast|overlaps|partition|posix)\b - statement.built_in: \b(precondition|preconditionFailure|print|println|quickSort|readLine|reduce|reflect)\b - statement.built_in: \b(reinterpretCast!reverse|roundUpToAlignment|sizeof|sizeofValue|sort|split|startsWith|stride)\b - statement.built_in: \b(strideof|strideofValue|swap|toString|transcode|underestimateCount|unsafeAddressOf|unsafeBitCast)\b - statement.built_in: \b(unsafeDowncast|unsafeUnwrap|unsafeReflect|withExtendedLifetime|withObjectAtPlusZero|withUnsafePointer)\b - statement.built_in: \b(withUnsafePointerToObject|withUnsafeMutablePointer|withUnsafeMutablePointers|withUnsafePointer)\b - statement.built_in: \b(withUnsafePointers|withVaList|zip)\b # Meta - statement.meta: \@\b(autoclosure|available|convention|exported|IBAction|IBDesignable|IBOutlet|IBInspectable|infix)\b - statement.meta: \@\b(lazy|noreturn|noescape|nonobjc|NSApplicationMain|NSCopying|NSManaged|objc|prefix|postfix)\b - statement.meta: \@\b(required|testable|warn_unused_result|UIApplicationMain)\b #preprocessor - preproc: ^[[:space:]]*#[[:space:]]*(define|else|elseif|endif|if|selector)\b - preproc.DebugIdentifier: \b(__COLUMN__|__FILE__|__FUNCTION__|__LINE__)\b - preproc.DebugIdentifier: ^[[:space:]]*#[[:space:]]*(column|file|function|line)\b # Constant - constant: \b(true|false|nil) - constant.number: ([0-9]+) # Storage Types - type.storage: \b((U)?Int(8|16|32|64))\b - type.storage: \b(Int|UInt|String|Bit|Bool|Character|Double|Optional|Float|Range)\b - type.storage: \b(AnyObject)\b # Collections - type.collections: \b(Array|Dictionary|Set)\b # Ctypes - type.ctypes: \b(CBool|CChar|CUnsignedChar|CShort|CUnsignedShort|CInt|CUnsignedInt|CLong|CUnsignedLong|CLongLong|CUnsignedLongLong|CWideChar|CChar16|CChar32|CFloat|CDouble)\b # String - constant.string: start: \" end: \" skip: \\. rules: - constant.specialChar: (\\0|\\\\|\\t|\\n|\\r|\\"|\\') - constant.interpolation: \\\([[:graph:]]*\) - constant.unicode: \\u\{[[:xdigit:]]+} # Shebang Line - comment.shebang: ^(#!).* # Doc Comment - comment.doc: (///).* # Line Comment - comment.line: "//.*" # Block Comment - comment.block: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" # Doc Block Comment - comment.block: start: "/\\*\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" # Todo - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/svelte.yaml0000664000175000017510000000100715125206537021440 0ustar nileshnileshfiletype: svelte detect: filename: "\\.svelte$" rules: - default: start: "" rules: - include: "javascript" - default: start: "" rules: - include: "typescript" - default: start: "" end: "" rules: - include: "css" - default: start: "^" end: "$" rules: - include: "html5" zyedidia-micro-6a62575/runtime/syntax/stata.yaml0000664000175000017510000004603315125206537021262 0ustar nileshnileshfiletype: stata detect: filename: "\\.a?do$" rules: - constant.string: start: "`\"" end: "\"'" rules: - identifier.macro: start: "`" end: "'" rules: [] - identifier.macro: "\\$\\w+" - constant.specialChar: "\\\\." - constant.string: start: "\"" end: "\"" rules: - identifier.macro: start: "`" end: "'" rules: [] - identifier.macro: "\\$\\w+" - constant.specialChar: "\\\\." # Built-in functions - identifier: "\\b(_caller|abbrev|abs|acos|acosh|asin|asinh|atan|atan2|atanh|autocode|betaden|binomial|binomialp|binomialtail|binormal|bofd|byteorder|c|cauchy|cauchyden|cauchytail|Cdhms|ceil|char|chi2|chi2den|chi2tail|Chms|cholesky|chop|clip|Clock|cloglog|Cmdyhms|Cofc|Cofd|coleqnumb|collatorlocale|collatorversion|colnfreeparms|colnumb|colsof|comb|cond|corr|cos|cosh|date|day|det|dgammapda|dgammapdada|dgammapdadx|dgammapdx|dgammapdxdx|dhms|diag|diag0cnt|digamma|dofb|dofC|dofh|dofm|dofq|dofw|dofy|dow|doy|dunnettprob|e|el|epsdouble|epsfloat|exp|exponential|exponentialden|exponentialtail|F|Fden|fileexists|fileread|filereaderror|filewrite|float|floor|fmtwidth|Ftail|gammaden|gammap|gammaptail|hadamard|halfyear|halfyearly|has_eprop|hh|hhC|hms|hofd|hours|hypergeometric|hypergeometricp|I|ibeta|ibetatail|igaussian|igaussianden|igaussiantail|indexnot|inlist|inrange|int|inv|invbinomial|invbinomialtail|invcauchy|invcauchytail|invchi2|invchi2tail|invcloglog|invdunnettprob|invexponential|invexponentialtail|invF|invFtail|invgammap|invgammaptail|invibeta|invibetatail|invigaussian|invigaussiantail|invlaplace|invlaplacetail|invlogistic|invlogistictail|invlogit|invnbinomial|invnbinomialtail|invnchi2|invnchi2tail|invnF|invnFtail|invnibeta|invnormal|invnt|invnttail|invpoisson|invpoissontail|invsym|invt|invttail|invtukeyprob|invweibull|invweibullph|invweibullphtail|invweibulltail|irecode|issymmetric|J|laplace|laplaceden|laplacetail|ln|lncauchyden|lnfactorial|lngamma|lnigammaden|lnigaussianden|lniwishartden|lnlaplaceden|lnmvnormalden|lnnormal|lnnormalden|lnwishartden|log|log10|logistic|logisticden|logistictail|logit|matmissing|matrix|matuniform|max|maxbyte|maxdouble|maxfloat|maxint|maxlong|mdy|mdyhms|missing|min|minbyte|mindouble|minfloat|minint|minlong|minutes|mm|mmC|mod|mofd|month|monthly|mreldif|msofhours|msofminutes|msofseconds|nbetaden|nbinomial|nbinomialp|nbinomialtail|nchi2|nchi2den|nchi2tail|nF|nFden|nFtail|nibeta|normal|normalden|npnchi2|npnF|npnt|nt|ntden|nttail|nullmat|plural|poisson|poissonp|poissontail|qofd|quarter|quarterly|r|rbeta|rbinomial|rcauchy|rchi2|real|recode|regexm|regexr|regexs|reldif|replay|return|rexponential|rgamma|rhypergeometric|rigaussian|rlaplace|rlogistic|rnbinomial|rnormal|round|roweqnumb|rownfreeparms|rownumb|rowsof|rpoisson|rt|runiform|runiformint|rweibull|rweibullph|s|scalar|seconds|sign|sin|sinh|smallestdouble|soundex|sqrt|ss|ssC|strcat|strdup|strofreal|string|strtrim|stritrim|strltrim|strrtrim|strlen|strupper|strlower|strproper|strmatch|strpos|strrpos|strreverse|strtoname|subinstr|subinword|substr|sum|sweep|t|tan|tanh|tC|td|tden|th|tin|tm|tobytes|tq|trace|trigamma|ttail|tukeyprob|tw|twithin|uchar|udstrlen|udsubstr|uisdigit|uisletter|ustrcompare|ustrsortkey|ustrcompareex|ustrsortkeyex|ustrfix|ustrto|ustrfrom|ustrlen|ustrinvalidcnt|usubstr|ustrleft|ustrright|ustrupper|ustrlower|ustrtitle|ustrtrim|ustrltrim|ustrrtrim|ustrnormalize|ustrpos|ustrrpos|ustrregexm|ustrregexrf|ustrregexra|ustrregexs|ustrreverse|ustrunescape|ustrtohex|ustrtoname|ustrword|ustrwordcount|usubinstr|vec|vecdiag|week|weekly|weibull|weibullden|weibullph|weibullphden|weibullphtail|weibulltail|wofd|word|wordbreaklocale|year|yearly|yh|ym|yofd|yq|yw)\\b" # Built-in commands - statement: "\\b(if|else|else\\s+if|in|foreach|for|forv|forva|forval|forvalu|forvalue|forvalues|by|bys|bysort|quietly|qui|about|ac|ac_7|acprplot|acprplot_7|adjust|ado|adopath|adoupdate|alpha|ameans|an|ano|anov|anova|anova_estat|anova_terms|anovadef|aorder|ap|app|appe|appen|append|arch|arch_dr|arch_estat|arch_p|archlm|areg|areg_p|args|arima|arima_dr|arima_estat|arima_p|as|asmprobit|asmprobit_estat|asmprobit_lf|asmprobit_mfx__dlg|asmprobit_p|ass|asse|asser|assert|avplot|avplot_7|avplots|avplots_7|bcskew0|bgodfrey|binreg|bip0_lf|biplot|bipp_lf|bipr_lf|bipr_p|biprobit|bitest|bitesti|bitowt|blogit|bmemsize|boot|bootsamp|bootstrap|bootstrap_8|boxco_l|boxco_p|boxcox|boxcox_6|boxcox_p|bprobit|br|break|brier|bro|brow|brows|browse|brr|brrstat|bs|bs_7|bsampl_w|bsample|bsample_7|bsqreg|bstat|bstat_7|bstat_8|bstrap|bstrap_7|ca|ca_estat|ca_p|cabiplot|camat|canon|canon_8|canon_8_p|canon_estat|canon_p|cap|caprojection|capt|captu|captur|capture|cat|cc|cchart|cchart_7|cci|cd|censobs_table|centile|cf|char|chdir|checkdlgfiles|checkestimationsample|checkhlpfiles|checksum|chelp|ci|cii|cl|class|classutil|clear|cli|clis|clist|clo|clog|clog_lf|clog_p|clogi|clogi_sw|clogit|clogit_lf|clogit_p|clogitp|clogl_sw|cloglog|clonevar|clslistarray|cluster|cluster_measures|cluster_stop|cluster_tree|cluster_tree_8|clustermat|cmdlog|cnr|cnre|cnreg|cnreg_p|cnreg_sw|cnsreg|codebook|collaps4|collapse|colormult_nb|colormult_nw|compare|compress|conf|confi|confir|confirm|conren|cons|const|constr|constra|constrai|constrain|constraint|continue|contract|copy|copyright|copysource|cor|corc|corr|corr2data|corr_anti|corr_kmo|corr_smc|corre|correl|correla|correlat|correlate|corrgram|cou|coun|count|cox|cox_p|cox_sw|coxbase|coxhaz|coxvar|cprplot|cprplot_7|crc|cret|cretu|cretur|creturn|cross|cs|cscript|cscript_log|csi|ct|ct_is|ctset|ctst_5|ctst_st|cttost|cumsp|cumsp_7|cumul|cusum|cusum_7|cutil|d|datasig|datasign|datasigna|datasignat|datasignatu|datasignatur|datasignature|datetof|db|dbeta|de|dec|deco|decod|decode|deff|des|desc|descr|descri|describ|describe|destring|dfbeta|dfgls|dfuller|di|di_g|dir|dirstats|dis|discard|disp|disp_res|disp_s|displ|displa|display|distinct|do|doe|doed|doedi|doedit|dotplot|dotplot_7|dprobit|drawnorm|drop|ds|ds_util|dstdize|duplicates|durbina|dwstat|dydx|e|ed|edi|edit|egen|eivreg|emdef|end|en|enc|enco|encod|encode|eq|erase|ereg|ereg_lf|ereg_p|ereg_sw|ereghet|ereghet_glf|ereghet_glf_sh|ereghet_gp|ereghet_ilf|ereghet_ilf_sh|ereghet_ip|eret|eretu|eretur|ereturn|err|erro|error|est|est_cfexist|est_cfname|est_clickable|est_expand|est_hold|est_table|est_unhold|est_unholdok|estat|estat_default|estat_summ|estat_vce_only|esti|estimates|etodow|etof|etomdy|ex|exi|exit|expand|expandcl|fac|fact|facto|factor|factor_estat|factor_p|factor_pca_rotated|factor_rotate|factormat|fcast|fcast_compute|fcast_graph|fdades|fdadesc|fdadescr|fdadescri|fdadescrib|fdadescribe|fdasav|fdasave|fdause|fh_st|open|read|close|file|filefilter|fillin|find_hlp_file|findfile|findit|findit_7|fit|fl|fli|flis|flist|for5_0|form|forma|format|fpredict|frac_154|frac_adj|frac_chk|frac_cox|frac_ddp|frac_dis|frac_dv|frac_in|frac_mun|frac_pp|frac_pq|frac_pv|frac_wgt|frac_xo|fracgen|fracplot|fracplot_7|fracpoly|fracpred|fron_ex|fron_hn|fron_p|fron_tn|fron_tn2|frontier|ftodate|ftoe|ftomdy|ftowdate|g|gamhet_glf|gamhet_gp|gamhet_ilf|gamhet_ip|gamma|gamma_d2|gamma_p|gamma_sw|gammahet|gdi_hexagon|gdi_spokes|ge|gen|gene|gener|genera|generat|generate|genrank|genstd|genvmean|gettoken|gl|gladder|gladder_7|glim_l01|glim_l02|glim_l03|glim_l04|glim_l05|glim_l06|glim_l07|glim_l08|glim_l09|glim_l10|glim_l11|glim_l12|glim_lf|glim_mu|glim_nw1|glim_nw2|glim_nw3|glim_p|glim_v1|glim_v2|glim_v3|glim_v4|glim_v5|glim_v6|glim_v7|glm|glm_6|glm_p|glm_sw|glmpred|glo|glob|globa|global|glogit|glogit_8|glogit_p|gmeans|gnbre_lf|gnbreg|gnbreg_5|gnbreg_p|gomp_lf|gompe_sw|gomper_p|gompertz|gompertzhet|gomphet_glf|gomphet_glf_sh|gomphet_gp|gomphet_ilf|gomphet_ilf_sh|gomphet_ip|gphdot|gphpen|gphprint|gprefs|gprobi_p|gprobit|gprobit_8|gr|gr7|gr_copy|gr_current|gr_db|gr_describe|gr_dir|gr_draw|gr_draw_replay|gr_drop|gr_edit|gr_editviewopts|gr_example|gr_example2|gr_export|gr_print|gr_qscheme|gr_query|gr_read|gr_rename|gr_replay|gr_save|gr_set|gr_setscheme|gr_table|gr_undo|gr_use|graph|graph7|grebar|greigen|greigen_7|greigen_8|grmeanby|grmeanby_7|gs_fileinfo|gs_filetype|gs_graphinfo|gs_stat|gsort|gwood|h|hadimvo|hareg|hausman|haver|he|heck_d2|heckma_p|heckman|heckp_lf|heckpr_p|heckprob|hel|help|hereg|hetpr_lf|hetpr_p|hetprob|hettest|hexdump|hilite|hist|hist_7|histogram|hlogit|hlu|hmeans|hotel|hotelling|hprobit|hreg|hsearch|icd9|icd9_ff|icd9p|iis|impute|imtest|inbase|include|inf|infi|infil|infile|infix|inp|inpu|input|ins|insheet|insp|inspe|inspec|inspect|integ|inten|intreg|intreg_7|intreg_p|intrg2_ll|intrg_ll|intrg_ll2|ipolate|iqreg|ir|irf|irf_create|irfm|iri|is_svy|is_svysum|isid|istdize|ivprob_1_lf|ivprob_lf|ivprobit|ivprobit_p|ivreg|ivreg_footnote|ivtob_1_lf|ivtob_lf|ivtobit|ivtobit_p|jackknife|jacknife|jknife|jknife_6|jknife_8|jkstat|joinby|kalarma1|kap|kap_3|kapmeier|kappa|kapwgt|kdensity|kdensity_7|keep|ksm|ksmirnov|ktau|kwallis|l|la|lab|labe|label|labelbook|ladder|levels|levelsof|leverage|lfit|lfit_p|li|lincom|line|linktest|lis|list|lloghet_glf|lloghet_glf_sh|lloghet_gp|lloghet_ilf|lloghet_ilf_sh|lloghet_ip|llogi_sw|llogis_p|llogist|llogistic|llogistichet|lnorm_lf|lnorm_sw|lnorma_p|lnormal|lnormalhet|lnormhet_glf|lnormhet_glf_sh|lnormhet_gp|lnormhet_ilf|lnormhet_ilf_sh|lnormhet_ip|lnskew0|loadingplot|loc|loca|local|log|logi|logis_lf|logistic|logistic_p|logit|logit_estat|logit_p|loglogs|logrank|loneway|lookfor|lookup|lowess|lowess_7|lpredict|lrecomp|lroc|lroc_7|lrtest|ls|lsens|lsens_7|lsens_x|lstat|ltable|ltable_7|ltriang|lv|lvr2plot|lvr2plot_7|m|ma|mac|macr|macro|makecns|man|manova|manova_estat|manova_p|manovatest|mantel|mark|markin|markout|marksample|mat|mat_capp|mat_order|mat_put_rr|mat_rapp|mata|mata_clear|mata_describe|mata_drop|mata_matdescribe|mata_matsave|mata_matuse|mata_memory|mata_mlib|mata_mosave|mata_rename|mata_which|matalabel|matcproc|matlist|matname|matr|matri|matrix|matrix_input__dlg|matstrik|mcc|mcci|md0_|md1_|md1debug_|md2_|md2debug_|mds|mds_estat|mds_p|mdsconfig|mdslong|mdsmat|mdsshepard|mdytoe|mdytof|me_derd|mean|means|median|memory|memsize|meqparse|mer|merg|merge|mfp|mfx|mhelp|mhodds|minbound|mixed_ll|mixed_ll_reparm|mkassert|mkdir|mkmat|mkspline|ml|ml_5|ml_adjs|ml_bhhhs|ml_c_d|ml_check|ml_clear|ml_cnt|ml_debug|ml_defd|ml_e0|ml_e0_bfgs|ml_e0_cycle|ml_e0_dfp|ml_e0i|ml_e1|ml_e1_bfgs|ml_e1_bhhh|ml_e1_cycle|ml_e1_dfp|ml_e2|ml_e2_cycle|ml_ebfg0|ml_ebfr0|ml_ebfr1|ml_ebh0q|ml_ebhh0|ml_ebhr0|ml_ebr0i|ml_ecr0i|ml_edfp0|ml_edfr0|ml_edfr1|ml_edr0i|ml_eds|ml_eer0i|ml_egr0i|ml_elf|ml_elf_bfgs|ml_elf_bhhh|ml_elf_cycle|ml_elf_dfp|ml_elfi|ml_elfs|ml_enr0i|ml_enrr0|ml_erdu0|ml_erdu0_bfgs|ml_erdu0_bhhh|ml_erdu0_bhhhq|ml_erdu0_cycle|ml_erdu0_dfp|ml_erdu0_nrbfgs|ml_exde|ml_footnote|ml_geqnr|ml_grad0|ml_graph|ml_hbhhh|ml_hd0|ml_hold|ml_init|ml_inv|ml_log|ml_max|ml_mlout|ml_mlout_8|ml_model|ml_nb0|ml_opt|ml_p|ml_plot|ml_query|ml_rdgrd|ml_repor|ml_s_e|ml_score|ml_searc|ml_technique|ml_unhold|mleval|mlf_|mlmatbysum|mlmatsum|mlog|mlogi|mlogit|mlogit_footnote|mlogit_p|mlopts|mlsum|mlvecsum|mnl0_|mor|more|mov|move|mprobit|mprobit_lf|mprobit_p|mrdu0_|mrdu1_|mvdecode|mvencode|mvreg|mvreg_estat|n|nbreg|nbreg_al|nbreg_lf|nbreg_p|nbreg_sw|nestreg|net|newey|newey_7|newey_p|news|nl|nl_7|nl_9|nl_9_p|nl_p|nl_p_7|nlcom|nlcom_p|nlexp2|nlexp2_7|nlexp2a|nlexp2a_7|nlexp3|nlexp3_7|nlgom3|nlgom3_7|nlgom4|nlgom4_7|nlinit|nllog3|nllog3_7|nllog4|nllog4_7|nlog_rd|nlogit|nlogit_p|nlogitgen|nlogittree|nlpred|no|nobreak|noi|nois|noisi|noisil|noisily|note|notes|notes_dlg|nptrend|numlabel|numlist|odbc|old_ver|olo|olog|ologi|ologi_sw|ologit|ologit_p|ologitp|on|one|onew|onewa|oneway|op_colnm|op_comp|op_diff|op_inv|op_str|opr|opro|oprob|oprob_sw|oprobi|oprobi_p|oprobit|oprobitp|opts_exclusive|order|orthog|orthpoly|ou|out|outf|outfi|outfil|outfile|outs|outsh|outshe|outshee|outsheet|ovtest|pac|pac_7|palette|parse|parse_dissim|pause|pca|pca_8|pca_display|pca_estat|pca_p|pca_rotate|pcamat|pchart|pchart_7|pchi|pchi_7|pcorr|pctile|pentium|pergram|pergram_7|permute|permute_8|personal|peto_st|pkcollapse|pkcross|pkequiv|pkexamine|pkexamine_7|pkshape|pksumm|pksumm_7|pl|plo|plot|plugin|pnorm|pnorm_7|poisgof|poiss_lf|poiss_sw|poisso_p|poisson|poisson_estat|post|postclose|postfile|postutil|pperron|pr|prais|prais_e|prais_e2|prais_p|predict|predictnl|preserve|print|pro|prob|probi|probit|probit_estat|probit_p|proc_time|procoverlay|procrustes|procrustes_estat|procrustes_p|profiler|prog|progr|progra|program|prop|proportion|prtest|prtesti|pwcorr|pwd|q|s|qby|qbys|qchi|qchi_7|qladder|qladder_7|qnorm|qnorm_7|qqplot|qqplot_7|qreg|qreg_c|qreg_p|qreg_sw|qu|quadchk|quantile|quantile_7|que|quer|query|range|ranksum|ratio|rchart|rchart_7|rcof|recast|reclink|recode|reg|reg3|reg3_p|regdw|regr|regre|regre_p2|regres|regres_p|regress|regress_estat|regriv_p|remap|ren|rena|renam|rename|renpfix|repeat|replace|report|reshape|restore|ret|retu|retur|return|rm|rmdir|robvar|roccomp|roccomp_7|roccomp_8|rocf_lf|rocfit|rocfit_8|rocgold|rocplot|rocplot_7|roctab|roctab_7|rolling|rologit|rologit_p|rot|rota|rotat|rotate|rotatemat|rreg|rreg_p|ru|run|runtest|rvfplot|rvfplot_7|rvpplot|rvpplot_7|sa|safesum|sample|sampsi|sav|save|savedresults|saveold|sc|sca|scal|scala|scalar|scatter|scm_mine|sco|scob_lf|scob_p|scobi_sw|scobit|scor|score|scoreplot|scoreplot_help|scree|screeplot|screeplot_help|sdtest|sdtesti|se|search|separate|seperate|serrbar|serrbar_7|serset|set|set_defaults|sfrancia|sh|she|shel|shell|shewhart|shewhart_7|signestimationsample|signrank|signtest|simul|simul_7|simulate|simulate_8|sktest|sleep|slogit|slogit_d2|slogit_p|smooth|snapspan|so|sor|sort|spearman|spikeplot|spikeplot_7|spikeplt|spline_x|split|sqreg|sqreg_p|sret|sretu|sretur|sreturn|ssc|st|st_ct|st_hc|st_hcd|st_hcd_sh|st_is|st_issys|st_note|st_promo|st_set|st_show|st_smpl|st_subid|stack|statsby|statsby_8|stbase|stci|stci_7|stcox|stcox_estat|stcox_fr|stcox_fr_ll|stcox_p|stcox_sw|stcoxkm|stcoxkm_7|stcstat|stcurv|stcurve|stcurve_7|stdes|stem|stepwise|stereg|stfill|stgen|stir|stjoin|stmc|stmh|stphplot|stphplot_7|stphtest|stphtest_7|stptime|strate|strate_7|streg|streg_sw|streset|sts|sts_7|stset|stsplit|stsum|sttocc|sttoct|stvary|stweib|su|suest|suest_8|sum|summ|summa|summar|summari|summariz|summarize|sunflower|sureg|survcurv|survsum|svar|svar_p|svmat|svy|svy_disp|svy_dreg|svy_est|svy_est_7|svy_estat|svy_get|svy_gnbreg_p|svy_head|svy_header|svy_heckman_p|svy_heckprob_p|svy_intreg_p|svy_ivreg_p|svy_logistic_p|svy_logit_p|svy_mlogit_p|svy_nbreg_p|svy_ologit_p|svy_oprobit_p|svy_poisson_p|svy_probit_p|svy_regress_p|svy_sub|svy_sub_7|svy_x|svy_x_7|svy_x_p|svydes|svydes_8|svygen|svygnbreg|svyheckman|svyheckprob|svyintreg|svyintreg_7|svyintrg|svyivreg|svylc|svylog_p|svylogit|svymarkout|svymarkout_8|svymean|svymlog|svymlogit|svynbreg|svyolog|svyologit|svyoprob|svyoprobit|svyopts|svypois|svypois_7|svypoisson|svyprobit|svyprobt|svyprop|svyprop_7|svyratio|svyreg|svyreg_p|svyregress|svyset|svyset_7|svyset_8|svytab|svytab_7|svytest|svytotal|sw|sw_8|swcnreg|swcox|swereg|swilk|swlogis|swlogit|swologit|swoprbt|swpois|swprobit|swqreg|swtobit|swweib|symmetry|symmi|symplot|symplot_7|syntax|sysdescribe|sysdir|sysuse|szroeter|ta|tab|tab1|tab2|tab_or|tabd|tabdi|tabdis|tabdisp|tabi|table|tabodds|tabodds_7|tabstat|tabu|tabul|tabula|tabulat|tabulate|te|tempfile|tempname|tempvar|tes|test|testnl|testparm|teststd|tetrachoric|time_it|timer|tis|tob|tobi|tobit|tobit_p|tobit_sw|token|tokeni|tokeniz|tokenize|tostring|total|translate|translator|transmap|treat_ll|treatr_p|treatreg|trim|trnb_cons|trnb_mean|trpoiss_d2|trunc_ll|truncr_p|truncreg|tsappend|tset|tsfill|tsline|tsline_ex|tsreport|tsrevar|tsrline|tsset|tssmooth|tsunab|ttest|ttesti|tut_chk|tut_wait|tutorial|tw|tware_st|two|twoway|twoway__fpfit_serset|twoway__function_gen|twoway__histogram_gen|twoway__ipoint_serset|twoway__ipoints_serset|twoway__kdensity_gen|twoway__lfit_serset|twoway__normgen_gen|twoway__pci_serset|twoway__qfit_serset|twoway__scatteri_serset|twoway__sunflower_gen|twoway_ksm_serset|ty|typ|type|typeof|u|unab|unabbrev|unabcmd|update|us|use|uselabel|var|var_mkcompanion|var_p|varbasic|varfcast|vargranger|varirf|varirf_add|varirf_cgraph|varirf_create|varirf_ctable|varirf_describe|varirf_dir|varirf_drop|varirf_erase|varirf_graph|varirf_ograph|varirf_rename|varirf_set|varirf_table|varlist|varlmar|varnorm|varsoc|varstable|varstable_w|varstable_w2|varwle|vce|vec|vec_fevd|vec_mkphi|vec_p|vec_p_w|vecirf_create|veclmar|veclmar_w|vecnorm|vecnorm_w|vecrank|vecstable|verinst|vers|versi|versio|version|view|viewsource|vif|vwls|wdatetof|webdescribe|webseek|webuse|weib1_lf|weib2_lf|weib_lf|weib_lf0|weibhet_glf|weibhet_glf_sh|weibhet_glfa|weibhet_glfa_sh|weibhet_gp|weibhet_ilf|weibhet_ilf_sh|weibhet_ilfa|weibhet_ilfa_sh|weibhet_ip|weibu_sw|weibul_p|weibull|weibull_c|weibull_s|weibullhet|wh|whelp|whi|which|whil|while|wilc_st|wilcoxon|win|wind|windo|window|winexec|wntestb|wntestb_7|wntestq|xchart|xchart_7|xcorr|xcorr_7|xi|xi_6|xmlsav|xmlsave|xmluse|xpose|xsh|xshe|xshel|xshell|xt_iis|xt_tis|xtab_p|xtabond|xtbin_p|xtclog|xtcloglog|xtcloglog_8|xtcloglog_d2|xtcloglog_pa_p|xtcloglog_re_p|xtcnt_p|xtcorr|xtdata|xtdes|xtfront_p|xtfrontier|xtgee|xtgee_elink|xtgee_estat|xtgee_makeivar|xtgee_p|xtgee_plink|xtgls|xtgls_p|xthaus|xthausman|xtht_p|xthtaylor|xtile|xtint_p|xtintreg|xtintreg_8|xtintreg_d2|xtintreg_p|xtivp_1|xtivp_2|xtivreg|xtline|xtline_ex|xtlogit|xtlogit_8|xtlogit_d2|xtlogit_fe_p|xtlogit_pa_p|xtlogit_re_p|xtmixed|xtmixed_estat|xtmixed_p|xtnb_fe|xtnb_lf|xtnbreg|xtnbreg_pa_p|xtnbreg_refe_p|xtpcse|xtpcse_p|xtpois|xtpoisson|xtpoisson_d2|xtpoisson_pa_p|xtpoisson_refe_p|xtpred|xtprobit|xtprobit_8|xtprobit_d2|xtprobit_re_p|xtps_fe|xtps_lf|xtps_ren|xtps_ren_8|xtrar_p|xtrc|xtrc_p|xtrchh|xtrefe_p|xtreg|xtreg_be|xtreg_fe|xtreg_ml|xtreg_pa_p|xtreg_re|xtregar|xtrere_p|xtset|xtsf_ll|xtsf_llti|xtsum|xttab|xttest0|xttobit|xttobit_8|xttobit_p|xttrans|yx|yxview__barlike_draw|yxview_area_draw|yxview_bar_draw|yxview_dot_draw|yxview_dropline_draw|yxview_function_draw|yxview_iarrow_draw|yxview_ilabels_draw|yxview_normal_draw|yxview_pcarrow_draw|yxview_pcbarrow_draw|yxview_pccapsym_draw|yxview_pcscatter_draw|yxview_pcspike_draw|yxview_rarea_draw|yxview_rbar_draw|yxview_rbarm_draw|yxview_rcap_draw|yxview_rcapsym_draw|yxview_rconnected_draw|yxview_rline_draw|yxview_rscatter_draw|yxview_rspike_draw|yxview_spike_draw|yxview_sunflower_draw|zap_s|zinb|zinb_llf|zinb_plf|zip|zip_llf|zip_p|zip_plf|zt_ct_5|zt_hc_5|zt_hcd_5|zt_is_5|zt_iss_5|zt_sho_5|zt_smp_5|ztbase_5|ztcox_5|ztdes_5|ztereg_5|ztfill_5|ztgen_5|ztir_5|ztjoin_5|ztnb|ztnb_p|ztp|ztp_p|zts_5|ztset_5|ztspli_5|ztsum_5|zttoct_5|ztvary_5|ztweib_5)\\b" - constant.number: "\\b[+-]?([0-9]+(\\.[0-9]+)?|\\.[0-9]+|\\.)([eE][+-]?[0-9]+)?[i]?\\b" - symbol.operator: "-|==|<=|>=|<|>|&|!=" - symbol.operator: "\\*|\\+|\\^|/|!|~|=|~=" - symbol.brackets: "[\\{\\}\\(\\)\\[\\]]" - identifier: "%-?\\d{1,2}(\\.\\d{1,2})?[gfe]c?" - identifier: "%(21x|16H|16L|8H|8L)" - identifier: "%-?(tc|tC|td|tw|tm|tq|th|ty|tg).{0,32}" - identifier: "%[-~]?\\d{1,4}s" - identifier.macro: "\\$\\w{1,32}" - identifier.macro: start: "`" end: "'" rules: [] - comment: start: "///?" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "^\\s*\\*" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/sql.yaml0000664000175000017510000000424415125206537020743 0ustar nileshnileshfiletype: sql detect: filename: "\\.sql$|sqliterc$" rules: - statement: "(?i)\\b(ALL|ASC|AS|ALTER|AND|ADD|AUTO_INCREMENT)\\b" - statement: "(?i)\\b(BETWEEN|BINARY|BOTH|BY|BOOLEAN)\\b" - statement: "(?i)\\b(CHANGE|CHECK|COLUMNS|COLUMN|CROSS|CREATE)\\b" - statement: "(?i)\\b(DATABASES|DATABASE|DATA|DELAYED|DESCRIBE|DESC|DISTINCT|DELETE|DROP|DEFAULT)\\b" - statement: "(?i)\\b(ENCLOSED|ESCAPED|EXISTS|EXPLAIN)\\b" - statement: "(?i)\\b(FIELDS|FIELD|FLUSH|FOR|FOREIGN|FUNCTION|FROM)\\b" - statement: "(?i)\\b(GROUP|GRANT|HAVING)\\b" - statement: "(?i)\\b(IGNORE|INDEX|INFILE|INSERT|INNER|INTO|IDENTIFIED|IN|IS|IF)\\b" - statement: "(?i)\\b(JOIN|KEYS|KILL|KEY)\\b" - statement: "(?i)\\b(LEADING|LIKE|LIMIT|LINES|LOAD|LOCAL|LOCK|LOW_PRIORITY|LEFT|LANGUAGE)\\b" - statement: "(?i)\\b(MODIFY|NATURAL|NOT|NULL|NEXTVAL)\\b" - statement: "(?i)\\b(OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUTFILE|OR|OUTER|ON)\\b" - statement: "(?i)\\b(PROCEDURE|PROCEDURAL|PRIMARY)\\b" - statement: "(?i)\\b(READ|REFERENCES|REGEXP|RENAME|REPLACE|RETURN|REVOKE|RLIKE|RIGHT)\\b" - statement: "(?i)\\b(SHOW|SONAME|STATUS|STRAIGHT_JOIN|SELECT|SETVAL|SET)\\b" - statement: "(?i)\\b(TABLES|TERMINATED|TO|TRAILING|TRUNCATE|TABLE|TEMPORARY|TRIGGER|TRUSTED)\\b" - statement: "(?i)\\b(UNIQUE|UNLOCK|USE|USING|UPDATE|VALUES|VARIABLES|VIEW)\\b" - statement: "(?i)\\b(WITH|WRITE|WHERE|ZEROFILL|TYPE|XOR)\\b" - type: "(?i)\\b(VARCHAR|TINYINT|TEXT|DATE|SMALLINT|MEDIUMINT|INT|INTEGER|BIGINT|FLOAT|DOUBLE|DECIMAL|DATETIME|TIMESTAMP|TIME|YEAR|UNSIGNED|CHAR|TINYBLOB|TINYTEXT|BLOB|MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|ENUM|BOOL|BINARY|VARBINARY)\\b" - preproc: "(?i)\\.\\b(databases|dump|echo|exit|explain|header(s)?|help)\\b" - preproc: "(?i)\\.\\b(import|indices|mode|nullvalue|output|prompt|quit|read)\\b" - preproc: "(?i)\\.\\b(schema|separator|show|tables|timeout|width)\\b" - constant.bool: "\\b(ON|OFF)\\b" - constant.number: "\\b([0-9]+)\\b" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - constant.string: "`(\\\\.|[^\\\\`])*`" - comment: "\\-\\-.*$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/solidity.yaml0000664000175000017510000000315115125206537022000 0ustar nileshnileshfiletype: solidity detect: filename: "\\.sol$" rules: - preproc: "\\b(contract|library|pragma)\\b" - constant.number: "\\b[-]?([0-9]+|0x[0-9a-fA-F]+)\\b" - identifier: "[a-zA-Z][_a-zA-Z0-9]*[[:space:]]*" - statement: "\\b(assembly|break|continue|do|for|function|if|else|new|return|returns|while)\\b" - special: "\\b(\\.send|throw)\\b" # make sure they are very visible - type.keyword: "\\b(anonymous|constant|indexed|payable|public|private|external|internal)\\b" - constant: "\\b(block(\\.(blockhash|coinbase|difficulty|gaslimit|number|timestamp))?|msg(\\.(data|gas|sender|value))?|now|tx(\\.(gasprice|origin))?)\\b" - constant: "\\b(keccak256|sha3|sha256|ripemd160|ecrecover|addmod|mulmod|this|super|selfdestruct|\\.balance)\\b" - constant: "\\b(true|false)\\b" - constant: "\\b(wei|szabo|finney|ether|seconds|minutes|hours|days|weeks|years)\\b" - type: "\\b(address|bool|mapping|string|var|int(\\d*)|uint(\\d*)|byte(\\d*)|fixed(\\d*)|ufixed(\\d*))\\b" - error: "\\b(abstract|after|case|catch|default|final|in|inline|interface|let|match|null|of|pure|relocatable|static|switch|try|type|typeof|view)\\b" - operator: "[-+/*=<>!~%?:&|]" - comment: start: "//" end: "$" rules: [] - comment: start: "/\\*" end: "\\*/" rules: [] - todo: "TODO:?" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." zyedidia-micro-6a62575/runtime/syntax/smalltalk.yaml0000664000175000017510000000342015125206537022123 0ustar nileshnileshfiletype: smalltalk detect: filename: "\\.(st|sources|changes)$" rules: - statement: "\\b(self|nil|true|false|ifTrue|ifFalse|whileTrue|whileFalse)\\b" - constant: "(\\$|@|@@)?\\b[A-Z]+[0-9A-Z_a-z]*" - constant.number: "(?i)\\b0x[0-9a-fA-F][0-9a-f_]*\\b" - constant.number: "(?i)\\b0b[01][01_]*\\b" - constant.number: "(?i)\\b[0-9][0-9_]*(['.'][0-9_]+)?(e[\\-]?[0-9_]+)?\\b" # Ruby "Symbols" - constant: "(i?)([ ]|^):[0-9A-Z_]+\\b" - constant: "\\b(__FILE__|__LINE__)\\b" - constant: "/([^/]|(\\\\/))*/[iomx]*|%r\\{([^}]|(\\\\}))*\\}[iomx]*" - constant.string: start: "'" end: "'" skip: "\\\\." rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - symbol.brackets: start: "#\\{" end: "\\}" rules: - default: ".*" - constant.string.exec: start: "`" end: "`" skip: "\\\\." rules: - symbol.brackets: start: "#\\{" end: "\\}" rules: - default: ".*" - constant.string: "%[QW]?\\{[^}]*\\}|%[QW]?\\([^)]*\\)|%[QW]?<[^>]*>|%[QW]?\\[[^]]*\\]|%[QW]?\\$[^$]*\\$|%[QW]?\\^[^^]*\\^|%[QW]?![^!]*!" - constant.string: "%[qw]\\{[^}]*\\}|%[qw]\\([^)]*\\)|%[qw]<[^>]*>|%[qw]\\[[^]]*\\]|%[qw]\\$[^$]*\\$|%[qw]\\^[^^]*\\^|%[qw]![^!]*!" - constant.string.exec: "%[x]\\{[^}]*\\}|%[x]\\([^)]*\\)|%[x]<[^>]*>|%[x]\\[[^]]*\\]|%[x]\\$[^$]*\\$|%[x]\\^[^^]*\\^|%[x]![^!]*!" - symbol.operator: "[-+/*=<>!~%&|^]|\\b:" - symbol.brackets: "([(){}]|\\[|\\])" - constant.macro: start: "<<-?'?EOT'?" end: "^EOT" rules: [] - preproc.shebang: "^#!.+?( |$)" zyedidia-micro-6a62575/runtime/syntax/sls.yaml0000664000175000017510000000066515125206537020750 0ustar nileshnileshfiletype: salt detect: filename: "\\.sls$" rules: - identifier.var: "^[^ -].*:$" - identifier.var: ".*:" - default: "salt:" - constant.number: "/*[0-9]/*" - constant.bool: "\\b(True|False)\\b" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - special: "\\b(grain|grains|compound|pcre|grain_pcre|list|pillar)\\b" - comment: "^#.*" - statement: "\\b(if|elif|else|or|not|and|endif|end)\\b" zyedidia-micro-6a62575/runtime/syntax/sh.yaml0000664000175000017510000000520215125206537020551 0ustar nileshnileshfiletype: shell # Detection based on filename is rather complicated as there are many # different file extensions and special filenames in use. # This expressions aims to capture them all while not matching # filenames that coincidentally contain the same substring. # # File extensions: # * .sh # * .bash # * .ash # * .ebuild (Gentoo ebuild format) # # Special filenames: # * .bashrc, .bash_aliases, .bash_functions .bash_profile # * profile, .profile (/etc/profile or ~/.profile) # * Pkgfile # * pkgmk.conf # * rc.conf # * PKGBUILD (Arch Linux build scripts) # * APKBUILD # # Fix command (fc) files: # * bash-fc. (followed by a random string) detect: filename: "(\\.(sh|bash|ash|ebuild)$|(\\.bash(rc|_aliases|_functions|_profile)|\\.?profile|Pkgfile|pkgmk\\.conf|rc\\.conf|PKGBUILD|APKBUILD)$|bash-fc\\.)" header: "^#!.*/(env +)?(ba)?(a)?(mk)?sh( |$)" rules: # Numbers - constant.number: "\\b[0-9]+\\b" # Conditionals and control flow - statement: "\\b(break|case|continue|do|done|elif|else|esac|exec|exit|fi|for|function|if|in|return|select|then|trap|until|wait|while)\\b" - special: "[`$<>!=&~^\\{\\}\\(\\)\\;\\]\\[]+" # Shell commands - type: "\\b(cd|command|echo|eval|export|getopts|let|local|read|set|shift|time|umask|unset)\\b" # Common linux commands - type: "\\b((g|ig)?awk|bash|dash|find|getopt|\\w{0,4}grep|kill|killall|\\w{0,4}less|make|pkill|sed|sh|tar)\\b" # Coreutils commands - type: "\\b(base64|basename|cat|chcon|chgrp|chmod|chown|chroot|cksum|comm|cp|csplit|cut|date|dd|df|dir|dircolors|dirname|du|env|expand|expr|factor|false|fmt|fold|head|hostid|id|install|join|link|ln|logname|ls|md5sum|mkdir|mkfifo|mknod|mktemp|mv|nice|nl|nohup|nproc|numfmt|od|paste|pathchk|pinky|pr|printenv|printf|ptx|pwd|readlink|realpath|rm|rmdir|runcon|seq|(sha1|sha224|sha256|sha384|sha512)sum|shred|shuf|sleep|sort|split|stat|stdbuf|stty|sum|sync|tac|tail|tee|test|time|timeout|touch|tr|true|truncate|tsort|tty|uname|unexpand|uniq|unlink|users|vdir|wc|who|whoami|yes)\\b" # Conditional flags - statement: "(\\s|^)(--?[A-Za-z0-9][\\w-]*)" - identifier: "\\$\\{[\\w:!%&=+#~@*^$?, .\\-\\/\\[\\]]+\\}" - identifier: "\\$([0-9!#@*$?-]|[A-Za-z_]\\w*)" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: [] - constant.string: start: "'" end: "'" skip: "\\\\." rules: [] - constant.string: start: "<<[^\\s]+[-~.]*[A-Za-z0-9]+$" end: "^[^\\s]+[A-Za-z0-9]+$" skip: "\\\\." rules: [] - comment: start: "(^|\\s)#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/sed.yaml0000664000175000017510000000051415125206537020713 0ustar nileshnileshfiletype: sed detect: filename: "\\.sed$" header: "^#!.*bin/(env +)?sed( |$)" rules: - symbol.operator: "[|^$.*+]" - constant.number: "\\{[0-9]+,?[0-9]*\\}" - constant.specialChar: "\\\\." - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/scala.yaml0000664000175000017510000000200415125206537021217 0ustar nileshnileshfiletype: scala detect: filename: "\\.sc(ala)?$|\\.sbt$" rules: - type: "\\b(boolean|byte|char|double|float|int|long|new|short|this|transient|void)\\b" - statement: "\\b(match|val|var|break|case|catch|continue|default|do|else|finally|for|if|return|switch|throw|try|while)\\b" - statement: "\\b(def|object|case|trait|lazy|implicit|abstract|class|extends|with|final|implements|override|import|instanceof|interface|native|package|private|protected|public|static|strictfp|super|synchronized|throws|volatile|sealed)\\b" - constant.string: start: "\"\"\"" end: "\"\"\"" rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant: "\\b(true|false|null)\\b" - comment: start: "//" end: "$" rules: [] - comment: start: "/\\*" end: "\\*/" rules: [] - comment: start: "/\\*\\*" end: "\\*/" rules: [] zyedidia-micro-6a62575/runtime/syntax/scad.yaml0000664000175000017510000000361015125206537021052 0ustar nileshnileshfiletype: OpenSCAD # OpenSCAD is a functional programming language used for representing # 2D/3D models for use in the program of the same name. # # The following documents were used as reference material: # https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language # https://openscad.org/cheatsheet/index.html detect: filename: "\\.scad$" rules: - identifier: "\\b(function|module) +[a-z0-9_]+" - statement: "\\b(abs|acos|asin|assert|atan|atan2|ceil|child|children|chr|circle|color|concat|cos|cross|cube|cylinder|difference|dxf_cross|dxf_dim|each|echo|else|exp|floor|for|function|hull|if|import|import_dxf|intersection|intersection_for|is_bool|is_function|is_list|is_num|is_string|is_undef|len|let|linear_extrude|ln|log|lookup|max|min|minkowski|mirror|module|multmatrix|norm|offset|ord|parent_module|polygon|polyhedron|pow|projection|rands|render|resize|rotate|rotate_extrude|round|scale|search|sign|sin|sphere|sqrt|square|str|surface|tan|text|translate|union|version|version_num)\\b" - symbol: "[,\\.;:?]" - symbol.operator: "[-+*/%^<>!=]|[<=>!]=|&&|\\|\\|" - symbol.brackets: "[{(<>)}]|\\[|\\]" # modifiers that change interpretation of the subtree after it - special: "[#%!*]" # special variables start with a dollar sign - special: "\\B\\$[a-z]+\\b" - preproc: start: "^ *(use|include) <" end: ">;?" rules: [] - constant.number: "\\b[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?|PI|inf|nan\\b" - constant.bool: "\\b(true|false)\\b" - constant: "\\b(undef)\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/sage.yaml0000664000175000017510000000474315125206537021067 0ustar nileshnileshfiletype: sage detect: filename: "\\.sage$" header: "^#!.*/(env +)?sage( |$)" rules: # built-in objects - constant: "\\b(None|self|True|False)\\b" # built-in attributes - constant: "\\b(__bases__|__builtin__|__class__|__debug__|__dict__|__doc__|__file__|__members__|__methods__|__name__|__self__)\\b" # built-in functions - identifier: "\\b(abs|apply|callable|chr|cmp|compile|delattr|dir|divmod|eval|exec|execfile|filter|format|getattr|globals|hasattr|hash|help|hex|id|input|intern|isinstance|issubclass|len|locals|max|min|next|oct|open|ord|pow|range|raw_input|reduce|reload|repr|round|setattr|unichr|vars|zip|__import__)\\b" # special method names - identifier: "\\b(__abs__|__add__|__and__|__call__|__cmp__|__coerce__|__complex__|__concat__|__contains__|__del__|__delattr__|__delitem__|__dict__|__delslice__|__div__|__divmod__|__float__|__getattr__|__getitem__|__getslice__|__hash__|__hex__|__init__|__int__|__inv__|__invert__|__len__|__long__|__lshift__|__mod__|__mul__|__neg__|__nonzero__|__oct__|__or__|__pos__|__pow__|__radd__|__rand__|__rcmp__|__rdiv__|__rdivmod__|__repeat__|__repr__|__rlshift__|__rmod__|__rmul__|__ror__|__rpow__|__rrshift__|__rshift__|__rsub__|__rxor__|__setattr__|__setitem__|__setslice__|__str__|__sub__|__xor__)\\b" # types - type: "\\b(basestring|bool|buffer|bytearray|bytes|classmethod|complex|dict|enumerate|file|float|frozenset|int|list|long|map|memoryview|object|property|reversed|set|slice|staticmethod|str|super|tuple|type|unicode|xrange)\\b" # definitions - identifier: "def [a-zA-Z_0-9]+" # keywords - statement: "\\b(and|as|assert|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield)\\b" # decorators - brightgreen: "@.*[(]" # operators - statement: "([.:;,+*|=!\\%@]|<|>|/|-|&)" # parentheses - statement: "([(){}]|\\[|\\])" # numbers - constant.number: "\\b[0-9]+\\b" - comment: start: "\"\"\"" end: "\"\"\"" rules: [] - comment: start: "'''" end: "'''" rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/rust.yaml0000664000175000017510000000415415125206537021141 0ustar nileshnileshfiletype: rust detect: filename: "\\.rs$" rules: # function definition - identifier: "fn [a-z0-9_]+" # Reserved words - statement: "\\b(abstract|alignof|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|false|final|fn|for|gen|if|impl|in|let|loop|macro|match|mod|move|mut|offsetof|override|priv|pub|pure|ref|return|sizeof|static|self|struct|super|true|trait|type|typeof|try|union|unsafe|unsized|use|virtual|where|while|yield)\\b" # macros - special: "[a-z_]+!" # Constants - constant: "\\b[A-Z][A-Z_0-9]+\\b" # Numbers - constant.number: "\\b[0-9]+\\b" # Booleans - constant: "\\b(true|false)\\b" # Traits/Enums/Structs/Types/etc. - type: "\\b[A-Z]+[a-zA-Z_0-9]*[a-z]+[a-zA-Z_0-9]*\\b" # Builtin types that start with lowercase. - type: "\\b(bool|str|char|((i|u)(8|16|32|64|128|size))|f(16|32|64|128))\\b" - constant.string: start: "[bc]?\"" end: "\"" skip: '\\.' rules: - constant.specialChar: '\\.' - constant.string: start: "[bc]?r#\"" end: "\"#" rules: [] - constant.string: start: "[bc]?r##\"" end: "\"##" rules: [] - constant.string: start: "[bc]?r###\"" end: "\"###" rules: [] - constant.string: start: "[bc]?r####+\"" end: "\"####+" rules: [] # Character literals # NOTE: This is an ugly hack to work around the fact that rust uses # single quotes both for character literals and lifetimes. # Match all character literals. - constant.string: "'(\\\\.|.)'" # Match the '"' literal which would otherwise match # as a double quoted string and destroy the highlighting. - constant.string: start: "'\"" end: "'" rules: [] - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" - special: start: "#!\\[" end: "\\]" rules: [] zyedidia-micro-6a62575/runtime/syntax/ruby.yaml0000664000175000017510000000504115125206537021121 0ustar nileshnileshfiletype: ruby detect: filename: "\\.(rb|rake|gemspec)$|^(.*[\\/])?(Gemfile|config.ru|Rakefile|Capfile|Vagrantfile|Guardfile|Appfile|Fastfile|Pluginfile|Podfile|\\.?[Bb]rewfile)$" header: "^#!.*/(env +)?ruby( |$)" rules: - comment.bright: start: "##" end: "$" rules: - todo: "(XXX|TODO|FIXME|BUG|\\?\\?\\?)" - comment: start: "#" end: "$" rules: - todo: "(XXX|TODO|FIXME|BUG|\\?\\?\\?)" - statement: "\\b(BEGIN|END|alias|and|begin|break|case|class|def|defined\\?|do|else|elsif|end|ensure|for|if|in|module|next|nil|not|or|private|protected|public|redo|rescue|retry|return|self|super|then|undef|unless|until|when|while|yield)\\b" - constant: "(\\$|@|@@)?\\b[A-Z]+[0-9A-Z_a-z]*" - constant.number: "(?i)\\b0x[0-9a-fA-F][0-9a-f_]*\\b" - constant.number: "(?i)\\b0b[01][01_]*\\b" - constant.number: "(?i)\\b[0-9][0-9_]*(['.'][0-9_]+)?(e[\\-]?[0-9_]+)?\\b" # Predefined global variables - constant: start: "[$]([!@&`'+~=/\\\\,;.<>*$?:\"_]|-[A-Za-z0-9_]|[0-9]+)" end: "\\B|\\b" rules: [] # Ruby "Symbols" - constant: "(i?)([ ]|^):[0-9A-Z_]+\\b" - constant: "\\b(__FILE__|__LINE__)\\b" - constant: "/([^/]|(\\\\/))*/[iomx]*|%r\\{([^}]|(\\\\}))*\\}[iomx]*" - constant.string: start: "'" end: "'" skip: "\\\\." rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - symbol.brackets: start: "#\\{" end: "\\}" rules: - default: ".*" - constant.string.exec: start: "`" end: "`" skip: "\\\\." rules: - symbol.brackets: start: "#\\{" end: "\\}" rules: - default: ".*" - constant.string: "%[QW]?\\{[^}]*\\}|%[QW]?\\([^)]*\\)|%[QW]?<[^>]*>|%[QW]?\\[[^]]*\\]|%[QW]?\\$[^$]*\\$|%[QW]?\\^[^^]*\\^|%[QW]?![^!]*!" - constant.string: "%[qw]\\{[^}]*\\}|%[qw]\\([^)]*\\)|%[qw]<[^>]*>|%[qw]\\[[^]]*\\]|%[qw]\\$[^$]*\\$|%[qw]\\^[^^]*\\^|%[qw]![^!]*!" - constant.string.exec: "%[x]\\{[^}]*\\}|%[x]\\([^)]*\\)|%[x]<[^>]*>|%[x]\\[[^]]*\\]|%[x]\\$[^$]*\\$|%[x]\\^[^^]*\\^|%[x]![^!]*!" - constant.bool: "\\b(true|false|nil|TRUE|FALSE|NIL)\\b" - symbol.operator: "[-+/*=<>!~%&|^]|\\b:" - symbol.brackets: "([(){}]|\\[|\\])" - constant.macro: start: "<<-?'?EOT'?" end: "^EOT" rules: [] - preproc.shebang: "^#!.+?( |$)" zyedidia-micro-6a62575/runtime/syntax/rpmspec.yaml0000664000175000017510000000341115125206537021610 0ustar nileshnileshfiletype: rpmspec detect: filename: "\\.spec$|\\.rpmspec$" rules: - preproc: "\\b(Icon|ExclusiveOs|ExcludeOs):" - preproc: "\\b(BuildArch|BuildArchitectures|ExclusiveArch|ExcludeArch):" - preproc: "\\b(Conflicts|Obsoletes|Provides|Requires|Requires\\(.*\\)|Enhances|Suggests|BuildConflicts|BuildRequires|Recommends|PreReq|Supplements):" - preproc: "\\b(Epoch|Serial|Nosource|Nopatch):" - preproc: "\\b(AutoReq|AutoProv|AutoReqProv):" - preproc: "\\b(Copyright|License|Summary|Summary\\(.*\\)|Distribution|Vendor|Packager|Group|Source[0-9]*|Patch[0-9]*|BuildRoot|Prefix):" - preproc: "\\b(Name|Version|Release|Url|URL):" - preproc: start: "^(Source|Patch)" end: ":" rules: [] - preproc: "(i386|i486|i586|i686|athlon|ia64|alpha|alphaev5|alphaev56|alphapca56|alphaev6|alphaev67|sparc|sparcv9|sparc64armv3l|armv4b|armv4lm|ips|mipsel|ppc|ppc|iseries|ppcpseries|ppc64|m68k|m68kmint|Sgi|rs6000|i370|s390x|s390|noarch)" - preproc: "(ifarch|ifnarch|ifos|ifnos)" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - statement: "%(if|else|endif|define|global|undefine)" - statement: "%_?([A-Z_a-z_0-9_]*)" - statement: start: "%\\{" end: "\\}" rules: [] - statement: start: "%\\{__" end: "\\}" rules: [] - statement: "\\$(RPM_BUILD_ROOT)\\>" - special: "^%(build$|changelog|check$|clean$|description)" - special: "^%(files|install$|package|prep$)" - special: "^%(pre|preun|pretrans|post|postun|posttrans)" - special: "^%(trigger|triggerin|triggerpostun|triggerun|verifyscript)" - comment: "(^|[[:space:]])#([^{].*)?$" - constant: "^\\*.*$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" - todo: "TODO:?" zyedidia-micro-6a62575/runtime/syntax/renpy.yaml0000664000175000017510000000112415125206537021273 0ustar nileshnileshfiletype: renpy detect: filename: "\\.rpy$" rules: # Script language keywords. - statement: "\\b(python|init|early|define|default|label|call|jump|image|layeredimage|screen|style|transform|menu|show|hide|scene|at|with|zorder|behind|pause|play|stop|fadeout|fadein|queue)\\b" # ATL keywords. - type: "\\b(repeat|block|choice|parallel|(x|y|)(pos|offset|anchor|align|center|tile|zoom)|time|linear|easein|alpha|subpixel)\\b" - identifier: "\\bpersistent\\b" - special: "\\$ " # Tab characters are not allowed in Renpy scripts. - error: "\\t" - include: python zyedidia-micro-6a62575/runtime/syntax/reST.yaml0000664000175000017510000000063015125206537021014 0ustar nileshnileshfiletype: rst detect: filename: "\\.rest$|\\.rst$" rules: - statement: "\\*\\*[^*]+\\*\\*" - preproc: "::" - constant.string: "`[^`]+`_{1,2}" - constant.string: "``[^`]+``" - identifier: "^\\.\\. .*$" - identifier: "^__ .*$" - type: "^###+$" - type: "^\\*\\*\\*+$" - special: "^===+$" - special: "^---+$" - special: "^\\^\\^\\^+$" - special: "^\"\"\"+$" zyedidia-micro-6a62575/runtime/syntax/raku.yaml0000664000175000017510000000377315125206537021114 0ustar nileshnileshfiletype: raku detect: filename: "\\.(p(l|m|od)?6|raku(mod|doc|test)?|nqp)$" rules: - type: "\\b(accept|alarm|atan2|bin(d|mode)|c(aller|h(dir|mod|op|own|root)|lose(dir)?|onnect|os|rypt)|d(bm(close|open)|efined|elete|ie|o|ump)|e(ach|of|val|x(ec|ists|it|p))|f(cntl|ileno|lock|ork)|get(c|login|peername|pgrp|ppid|priority|pwnam|(host|net|proto|serv)byname|pwuid|grgid|(host|net)byaddr|protobynumber|servbyport)|([gs]et|end)(pw|gr|host|net|proto|serv)ent|getsock(name|opt)|gmtime|goto|grep|hex|index|int|ioctl|join|keys|kill|last|length|link|listen|local(time)?|log|lstat|m|mkdir|msg(ctl|get|snd|rcv)|next|oct|open(dir)?|ord|pack|pipe|pop|printf?|push|q|qq|qx|rand|re(ad(dir|link)?|cv|do|name|quire|set|turn|verse|winddir)|rindex|rmdir|s|scalar|seek|seekdir|se(lect|mctl|mget|mop|nd|tpgrp|tpriority|tsockopt)|shift|shm(ctl|get|read|write)|shutdown|sin|sleep|socket(pair)?|sort|spli(ce|t)|sprintf|sqrt|srand|stat|study|substr|symlink|sys(call|read|tem|write)|tell(dir)?|time|tr|y|truncate|umask|un(def|link|pack|shift)|utime|values|vec|wait(pid)?|wantarray|warn|write)\\b" - statement: "\\b(continue|else|elsif|do|for|foreach|if|unless|until|while|eq|ne|lt|gt|le|ge|cmp|x|my|sub|use|package|can|isa)\\b" - special: "\\b(has|is|class|role|given|when|BUILD|multi|returns|method|submethod|slurp|say|sub)\\b" - identifier: "[$@%&](\\.|!|\\^)?([[:alpha:]]|_)" - identifier: "[$@%&](\\.|!|^)?([[:alpha:]]|_)([[:alnum:]]|-|_)*([[:alnum:]]|_)" - identifier: "[$@%&](\\?|\\*)([A-Z])([A-Z]|-)*([A-Z])" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - preproc: start: "(^use| = new)" end: ";" rules: [] - identifier.macro: start: "<|/|-|&|\\^|\\$)" - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." zyedidia-micro-6a62575/runtime/syntax/python3.yaml0000664000175000017510000000545215125206537021552 0ustar nileshnileshfiletype: python detect: filename: "\\.py(3|w)?$" header: "^#!.*/(env +)?python(3)?$" rules: # built-in objects - constant: "\\b(Ellipsis|None|self|cls|True|False)\\b" # built-in attributes - constant: "\\b(__bases__|__builtin__|__class__|__debug__|__dict__|__doc__|__file__|__members__|__methods__|__name__|__self__)\\b" # built-in functions - identifier: "\\b(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dir|divmod|eval|exec|format|getattr|globals|hasattr|hash|help|hex|id|input|isinstance|issubclass|iter|len|locals|max|min|next|nonlocal|oct|open|ord|pow|print|repr|round|setattr|sorted|sum|vars|__import__)\\b" # special method names - identifier: "\\b__(abs|add|and|call|cmp|coerce|complex|concat|contains|delattr|delitem|delslice|del|dict|divmod|div|float|getattr|getitem|getslice|hash|hex|iadd|iand|iconcat|ifloordiv|ilshift|imatmul|imod|imul|init|int|invert|inv|ior|ipow|irshift|isub|iter|itruediv|ixor|len|long|lshift|mod|mul|neg|next|nonzero|oct|or|pos|pow|radd|rand|rcmp|rdivmod|rdiv|repeat|repr|rlshift|rmod|rmul|ror|rpow|rrshift|rshift|rsub|rxor|setattr|setitem|setslice|str|sub|xor)__\\b" # types - type: "\\b(bool|bytearray|bytes|classmethod|complex|dict|enumerate|filter|float|frozenset|int|list|map|memoryview|object|property|range|reversed|set|slice|staticmethod|str|super|tuple|type|zip)\\b" # definitions - identifier: "def [a-zA-Z_0-9]+" # keywords - statement: "\\b(and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|raise|return|try|while|with|yield)\\b" # decorators - preproc: "^\\s*@[^(]*" # operators - symbol.operator: "([~^.:;,+*|=!\\%@]|<|>|/|-|&)" # parentheses - symbol.brackets: "([(){}]|\\[|\\])" # numbers - constant.number: "\\b[0-9](_?[0-9])*(\\.([0-9](_?[0-9])*)?)?(e[0-9](_?[0-9])*)?\\b" # decimal - constant.number: "\\b0b(_?[01])+\\b" # bin - constant.number: "\\b0o(_?[0-7])+\\b" # oct - constant.number: "\\b0x(_?[0-9a-fA-F])+\\b" # hex - constant.string: start: "\"\"\"" end: "\"\"\"" rules: [] - constant.string: start: "'''" end: "'''" rules: [] - constant.string: start: "\"" end: "(\"|$)" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "('|$)" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: # AKA Code tags (PEP 350) - todo: "(TODO|FIXME|HACK|BUG|NOTE|FAQ|MNEMONIC|REQ|RFE|IDEA|PORT|\\?\\?\\?|!!!|GLOSS|SEE|TODOC|STAT|RVD|CRED):?" zyedidia-micro-6a62575/runtime/syntax/python2.yaml0000664000175000017510000000500115125206537021537 0ustar nileshnileshfiletype: python2 detect: filename: "\\.py2$" header: "^#!.*/(env +)?python2$" rules: # built-in objects - constant: "\\b(None|self|True|False)\\b" # built-in attributes - constant: "\\b(__bases__|__builtin__|__class__|__debug__|__dict__|__doc__|__file__|__members__|__methods__|__name__|__self__)\\b" # built-in functions - identifier: "\\b(abs|apply|callable|chr|cmp|compile|delattr|dir|divmod|eval|exec|execfile|filter|format|getattr|globals|hasattr|hash|help|hex|id|input|intern|isinstance|issubclass|len|locals|max|min|next|oct|open|ord|pow|range|raw_input|reduce|reload|repr|round|setattr|unichr|vars|zip|__import__)\\b" # special method names - identifier: "\\b(__abs__|__add__|__and__|__call__|__cmp__|__coerce__|__complex__|__concat__|__contains__|__del__|__delattr__|__delitem__|__dict__|__delslice__|__div__|__divmod__|__float__|__getattr__|__getitem__|__getslice__|__hash__|__hex__|__init__|__int__|__inv__|__invert__|__len__|__long__|__lshift__|__mod__|__mul__|__neg__|__nonzero__|__oct__|__or__|__pos__|__pow__|__radd__|__rand__|__rcmp__|__rdiv__|__rdivmod__|__repeat__|__repr__|__rlshift__|__rmod__|__rmul__|__ror__|__rpow__|__rrshift__|__rshift__|__rsub__|__rxor__|__setattr__|__setitem__|__setslice__|__str__|__sub__|__xor__)\\b" # types - type: "\\b(basestring|bool|buffer|bytearray|bytes|classmethod|complex|dict|enumerate|file|float|frozenset|int|list|long|map|memoryview|object|property|reversed|set|slice|staticmethod|str|super|tuple|type|unicode|xrange)\\b" # definitions - identifier: "def [a-zA-Z_0-9]+" # keywords - statement: "\\b(and|as|assert|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield)\\b" # decorators - preproc: "^\\s*@[^(]*" # operators - symbol.operator: "([.:;,+*|=!\\%@]|<|>|/|-|&)" # parentheses - symbol.brackets: "([(){}]|\\[|\\])" # numbers - constant.number: "\\b[0-9]+\\b" - constant.string: start: "\"\"\"" end: "\"\"\"" rules: [] - constant.string: start: "'''" end: "'''" rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/puppet.yaml0000664000175000017510000000277515125206537021470 0ustar nileshnileshfiletype: puppet detect: filename: "\\.pp$" rules: - default: "^[[:space:]]([a-z][a-z0-9_]+)" - identifier.var: "\\$[a-z:][a-z0-9_:]+" - type: "\\b(augeas|computer|cron|exec|file|filebucket|group|host|interface|k5login|macauthorization|mailalias|maillist|mcx|mount|nagios_command|nagios_contact|nagios_contactgroup|nagios_host|nagios_hostdependency|nagios_hostescalation|nagios_hostextinfo|nagios_hostgroup|nagios_service|nagios_servicedependency|nagios_serviceescalation|nagios_serviceextinfo|nagios_servicegroup|nagios_timeperiod|notify|package|resources|router|schedule|scheduled_task|selboolean|selmodule|service|ssh_authorized_key|sshkey|stage|tidy|user|vlan|yumrepo|zfs|zone|zpool|anchor)\\b" - statement: "\\b(class|define|if|else|undef|inherits)\\b" - symbol: "(=|-|~|>)" - identifier.var: "(\\$|@|@@)?\\b[A-Z]+[0-9A-Z_a-z]*" - symbol: "([ ]|^):[0-9A-Z_]+\\b" - constant: "/([^/]|(\\\\/))*/[iomx]*|%r\\{([^}]|(\\\\}))*\\}[iomx]*" - constant.string: "`[^`]*`|%x\\{[^}]*\\}" - constant.string: "\"([^\"]|(\\\\\"))*\"|%[QW]?\\{[^}]*\\}|%[QW]?\\([^)]*\\)|%[QW]?<[^>]*>|%[QW]?\\[[^]]*\\]|%[QW]?\\$[^$]*\\$|%[QW]?\\^[^^]*\\^|%[QW]?![^!]*!" - special: "\\$\\{[^}]*\\}" - constant.string: "'([^']|(\\\\'))*'|%[qw]\\{[^}]*\\}|%[qw]\\([^)]*\\)|%[qw]<[^>]*>|%[qw]\\[[^]]*\\]|%[qw]\\$[^$]*\\$|%[qw]\\^[^^]*\\^|%[qw]![^!]*!" - comment: "#[^{].*$|#$" - comment.bright: "##[^{].*$|##$" - todo: "(XXX|TODO|FIXME|\\?\\?\\?)" - indent-char.whitespace: "[[:space:]]+$" zyedidia-micro-6a62575/runtime/syntax/prql.yaml0000664000175000017510000000571115125206537021122 0ustar nileshnilesh# https://prql-lang.org/ # https://github.com/PRQL/prql filetype: prql detect: filename: "\\.prql$" rules: - statement: "\\b(let|module|into|case|type|func)\\b" # Types - type: "\\b(u?int(8|16|32|64)?|float(32|64)|bool|text|date|time|timestamp)\\b" - type.keyword: "\\b(enum)\\b" - constant.bool: "\\b(true|false|null|this|that)\\b" # Built-in functions - identifier: "\\b(abs|floor|ceil|pi|exp|ln|log10|log|sqrt|degrees|radians|cos|acos|sin|asin|tan|atan|pow|round)\\b" # Math module - identifier: "\\b(min|max|sum|average|stddev|all|any|concat_array|count)\\b" # Aggregate functions - identifier: "\\b(lag|lead|first|last|rank|rank_dense|row_number)\\b" # Window functions - identifier: "\\b(tuple_every|tuple_map|tuple_zip|_eq|_is_null)\\b" # Tuple functions - identifier: "\\b(as|in|from_text)\\b" # Misc - identifier: "\\b(lower|upper|ltrim|rtrim|trim|length|extract|replace|starts_with|contains|ends_with)\\b" # Text module - identifier: "\\b(to_text)\\b" # Date module - identifier: "\\b(read_parquet|read_csv)\\b" # File-reading functions # Modules - identifier.class: "\\b(math|text|date|prql)\\b" # Transforms - statement: "\\b(aggregate|derive|filter|from|group|join|select|sort|take|window)\\b" # Operators - symbol.operator: "([~^.:;,+*|=!\\%@?]|<|>|/|-|&)" # Brackets - symbol.brackets: "[{}()\\[\\]]" # Numbers - constant.number: "\\b[0-9](_?[0-9])*(\\.([0-9](_?[0-9])*)?)?(e[0-9](_?[0-9])*)?\\b" # decimal - constant.number: "\\b0b(_?[01])+\\b" # bin - constant.number: "\\b0o(_?[0-7])+\\b" # oct - constant.number: "\\b0x(_?[0-9a-fA-F])+\\b" # hex - constant: "\\b[0-9]+(years|months|weeks|days|hours|minutes|seconds|milliseconds|microseconds)\\b" - constant.string: start: "[frs]?\"\"\"" end: "\"\"\"" skip: "\\\\." rules: - constant.specialChar: "\\\\[bfnrt'\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u\\{[0-9A-Fa-f]{1,6}\\})" - constant.string: start: "[frs]?'''" end: "'''" skip: "\\\\." rules: - constant.specialChar: "\\\\[bfnrt'\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u\\{[0-9A-Fa-f]{1,6}\\})" - constant.string: start: "[frs]?\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\[bfnrt'\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u\\{[0-9A-Fa-f]{1,6}\\})" - constant.string: start: "[frs]?'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\[bfnrt'\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u\\{[0-9A-Fa-f]{1,6}\\})" - comment: start: "#" end: "$" rules: - todo: "(TODO|FIXME|NOTE):?" # Decorators - preproc: "@\\{([a-z]+(=[a-z0-9]+,?)?)*\\}" zyedidia-micro-6a62575/runtime/syntax/proto.yaml0000664000175000017510000000201115125206537021275 0ustar nileshnileshfiletype: proto detect: filename: "(\\.(proto)$$)" rules: - identifier: "\\b[A-Z_][0-9A-Z_]+\\b" - type: "\\b(int(8|16|32|64))|string|bytes|repeated|bool|required|map|optional|oneof|union\\b" - statement: "\\b(import|service|enum|syntax|package|option|message|rpc|returns|extensions|to)\\b" - constant: "'\\\\(([0-3]?[0-7]{1,2}))'" - constant: "'\\\\x[0-9A-Fa-f]{1,2}'" - symbol.brackets: "[(){}]|\\[|\\]" - constant.number: "(\\b[0-9]+\\b|\\b0x[0-9A-Fa-f]+\\b)" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - preproc: "..+" - constant.specialChar: "\\\\." - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/privoxy-filter.yaml0000664000175000017510000000072015125206537023142 0ustar nileshnileshfiletype: privoxy-filter detect: filename: "\\.filter$" rules: - statement: "^(FILTER|CLIENT-HEADER-FILTER|CLIENT-HEADER-TAGGER|SERVER-HEADER-FILTER|SERVER-HEADER-TAGGER): [a-z-]+" - identifier: "^(FILTER|CLIENT-HEADER-FILTER|CLIENT-HEADER-TAGGER|SERVER-HEADER-FILTER|SERVER-HEADER-TAGGER):" - constant.specialChar: "\\\\.?" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/privoxy-config.yaml0000664000175000017510000000153715125206537023131 0ustar nileshnileshfiletype: privoxy-config detect: filename: "privoxy/config$" rules: - statement: "(accept-intercepted-requests|actionsfile|admin-address|allow-cgi-request-crunching|buffer-limit|compression-level|confdir|connection-sharing|debug|default-server-timeout|deny-access|enable-compression|enable-edit-actions|enable-remote-http-toggle|enable-remote-toggle|enforce-blocks|filterfile|forward|forwarded-connect-retries|forward-socks4|forward-socks4a|forward-socks5|handle-as-empty-doc-returns-ok|hostname|keep-alive-timeout|listen-address|logdir|logfile|max-client-connections|permit-access|proxy-info-url|single-threaded|socket-timeout|split-large-forms|templdir|toggle|tolerate-pipelining|trustfile|trust-info-url|user-manual)[[:space:]]" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/privoxy-action.yaml0000664000175000017510000000315115125206537023133 0ustar nileshnileshfiletype: privoxy-action detect: filename: "\\.action$" rules: - constant.bool.false: "[{[:space:]]\\-block([[:space:]{}]|$)" - constant.bool.true: "[{[:space:]]\\+block([[:space:]{}]|$)" - constant.bool.false: "-(add-header|change-x-forwarded-for|client-header-filter|client-header-tagger|content-type-overwrite|crunch-client-header|crunch-if-none-match|crunch-incoming-cookies|crunch-outgoing-cookies|crunch-server-header|deanimate-gifs|downgrade-http-version|fast-redirects|filter|force-text-mode|forward-override|handle-as-empty-document|handle-as-image|hide-accept-language|hide-content-disposition|hide-from-header|hide-if-modified-since|hide-referrer|hide-user-agent|limit-connect|overwrite-last-modified|prevent-compression|redirect|server-header-filter|server-header-tagger|session-cookies-only|set-image-blocker)" - constant.bool.true: "\\+(add-header|change-x-forwarded-for|client-header-filter|client-header-tagger|content-type-overwrite|crunch-client-header|crunch-if-none-match|crunch-incoming-cookies|crunch-outgoing-cookies|crunch-server-header|deanimate-gifs|downgrade-http-version|fast-redirects|filter|force-text-mode|forward-override|handle-as-empty-document|handle-as-image|hide-accept-language|hide-content-disposition|hide-from-header|hide-if-modified-since|hide-referrer|hide-user-agent|limit-connect|overwrite-last-modified|prevent-compression|redirect|server-header-filter|server-header-tagger|session-cookies-only|set-image-blocker)" - constant.specialChar: "\\\\.?" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/pov.yaml0000664000175000017510000000131515125206537020744 0ustar nileshnileshfiletype: pov detect: filename: "\\.(pov|POV|povray|POVRAY)$" rules: - preproc: "^[[:space:]]*#[[:space:]]*(declare)" - statement: "\\b(sphere|cylinder|translate|matrix|rotate|scale)\\b" - statement: "\\b(orthographic|location|up|right|direction|clipped_by)\\b" - statement: "\\b(fog_type|fog_offset|fog_alt|rgb|distance|transform)\\b" - identifier: "^\\b(texture)\\b" - identifier: "\\b(light_source|background)\\b" - identifier: "\\b(fog|object|camera)\\b" - symbol.operator: "(\\{|\\}|\\(|\\)|\\;|\\]|\\[|`|\\\\|\\$|<|>|!|=|&|\\|)" - special: "\\b(union|group|subgroup)\\b" - comment: "//.*" - comment: start: "/\\*" end: "\\*/" rules: [] zyedidia-micro-6a62575/runtime/syntax/pony.yaml0000664000175000017510000000241415125206537021126 0ustar nileshnileshfiletype: pony detect: filename: "\\.pony$" rules: - statement: "\\b(type|interface|trait|primitive|class|struct|actor)\\b" - statement: "\\b(compiler_intrinsic)\\b" - statement: "\\b(use)\\b" - statement: "\\b(var|let|embed)\\b" - statement: "\\b(new|be|fun)\\b" - statement: "\\b(iso|trn|ref|val|box|tag|consume)\\b" - statement: "\\b(break|continue|return|error)\\b" - statement: "\\b(if|then|elseif|else|end|match|where|try|with|as|recover|object|lambda|as|digestof|ifdef)\\b" - statement: "\\b(while|do|repeat|until|for|in)\\b" - statement: "(\\?|=>)" - statement: "(\\||\\&|\\,|\\^)" - symbol.operator: "(\\-|\\+|\\*|/|\\!|%|<<|>>)" - symbol.operator: "(==|!=|<=|>=|<|>)" - statement: "\\b(is|isnt|not|and|or|xor)\\b" - type: "\\b(_*[A-Z][_a-zA-Z0-9\\']*)\\b" - constant: "\\b(this)\\b" - constant.bool: "\\b(true|false)\\b" - constant.number: "\\b((0b[0-1_]*)|(0o[0-7_]*)|(0x[0-9a-fA-F_]*)|([0-9_]+(\\.[0-9_]+)?((e|E)(\\\\+|-)?[0-9_]+)?))\\b" - constant.string: "\"(\\\\.|[^\"])*\"" - comment: start: "\"\"\"[^\"]*" end: "\"\"\"" rules: [] - comment: "(^|[[:space:]])//.*" - comment: start: "/\\*" end: "\\*/" rules: [] - todo: "TODO:?" zyedidia-micro-6a62575/runtime/syntax/po.yaml0000664000175000017510000000045215125206537020557 0ustar nileshnileshfiletype: po detect: filename: "\\.pot?$" rules: - preproc: "\\b(msgid|msgstr)\\b" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - special: "\\\\.?" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/pkg-config.yaml0000664000175000017510000000051015125206537022160 0ustar nileshnileshfiletype: pc detect: filename: "\\.pc$" rules: - preproc: "^(Name|Description|URL|Version|Conflicts|Cflags):" - preproc: "^(Requires|Libs)(\\.private)?:" - symbol.operator: "=" - identifier.var: "\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/php.yaml0000664000175000017510000000575015125206537020736 0ustar nileshnileshfiletype: php detect: filename: "\\.php[2345s~]?$" rules: - symbol.operator: "<|>" - error: "<[^!].*?>" - symbol.tag: "(?i)<[/]?(a(bbr|cronym|ddress|pplet|rea|rticle|side|udio)?|b(ase(font)?|d(i|o)|ig|lockquote|r)?|ca(nvas|ption)|center|cite|co(de|l|lgroup)|d(ata(list)?|d|el|etails|fn|ialog|ir|l|t)|em(bed)?|fieldset|fig(caption|ure)|font|form|(i)?frame|frameset|h[1-6]|hr|i|img|in(put|s)|kbd|keygen|label|legend|li(nk)?|ma(in|p|rk)|menu(item)?|met(a|er)|nav|no(frames|script)|o(l|pt(group|ion)|utput)|p(aram|icture|re|rogress)?|q|r(p|t|uby)|s(trike)?|samp|se(ction|lect)|small|source|span|strong|su(b|p|mmary)|textarea|time|track|u(l)?|var|video|wbr)( .*|>)*?>" - symbol.tag.extended: "(?i)<[/]?(body|div|html|head(er)?|footer|title|table|t(body|d|h(ead)?|r|foot))( .*|>)*?>" - preproc: "(?i)<[/]?(script|style)( .*|>)*?>" - preproc: "<\\?(php|=)?" - preproc: "\\?>" - preproc: "" - special: "&[^;[[:space:]]]*;" - symbol: "[:=]" - identifier: "(alt|bgcolor|height|href|label|longdesc|name|onclick|onfocus|onload|onmouseover|size|span|src|style|target|type|value|width)=" - constant.number: "(?i)#[0-9a-fA-F]{6,6}" - constant.string.url: "(ftp(s)?|http(s)?|git|chrome)://[^ ]+" - comment: "" - default: "<\\?(php|=)\" end=\"\\?>" - identifier.class: "([a-zA-Z0-9_-]+)\\(" - type: "\\b(array|bool|callable|float|int|iterable|object|mixed|string|void)\\b" - identifier.class: "[a-zA-Z\\\\]+::" - identifier: "\\b([A-Z][a-zA-Z0-9_]+)\\b" - identifier: "([A-Z0-9_]+)[;|\\s|\\)|,]" - type.keyword: "\\b(global|final|public|private|protected|static|const|var)\\b" - statement: "\\b(abstract|catch|class|declare|do|else(if)?|end(declare|for(each)?|if|switch|while)|enum|finally|for(each)|function|if|interface|namespace|switch|trait|try|while)\\b" - identifier: "\\bnew\\s+([a-zA-Z0-9\\\\]+)" - special: "\\b(as|and|break|case|clone|continue|default|die|fn|echo|empty|eval|exit|extends|goto|or|include(_once)?|implements|instanceof|insteadof|isset|list|match|new|print|return|require(_once)?|unset|use|throw|xor|yield(\\s+from))\\b" - constant.bool: "\\b(true|false|null|TRUE|FALSE|NULL)\\b" - constant: "[\\s|=|\\s|\\(|/|+|-|\\*|\\[]" - constant.number: "[0-9]" - identifier: "(\\$this|parent|self|\\$this->)" - symbol.operator: "(=>|===|!==|==|!=|&&|\\|\\||::|=|->|\\!)" - identifier.var: "(\\$[a-zA-Z0-9\\-_]+)" - symbol.operator: "[\\(|\\)|/|+|\\-|\\*|\\[|.|,|;]" - symbol.brackets: "(\\[|\\]|\\{|\\}|[()])" - comment: start: "(^|[[:space:]])*(//|#)" end: "$" rules: [] - comment: start: "/\\*" end: "\\*/" rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" zyedidia-micro-6a62575/runtime/syntax/perl.yaml0000664000175000017510000000446415125206537021112 0ustar nileshnileshfiletype: perl detect: filename: "\\.p[lmp]$" header: "^#!.*/(env +)?perl( |$)" rules: - type: "\\b(accept|alarm|atan2|bin(d|mode)|c(aller|homp|h(dir|mod|op|own|root)|lose(dir)?|onnect|os|rypt)|d(bm(close|open)|efined|elete|ie|o|ump)|e(ach|of|val|x(ec|ists|it|p))|f(cntl|ileno|lock|ork))\\b|\\b(get(c|login|peername|pgrp|ppid|priority|pwnam|(host|net|proto|serv)byname|pwuid|grgid|(host|net)byaddr|protobynumber|servbyport)|([gs]et|end)(pw|gr|host|net|proto|serv)ent|getsock(name|opt)|gmtime|goto|grep|hex|index|int|ioctl|join)\\b|\\b(keys|kill|last|length|link|listen|local(time)?|log|lstat|m|mkdir|msg(ctl|get|snd|rcv)|next|oct|open(dir)?|ord|pack|pipe|pop|printf?|push|q|qq|qx|rand|re(ad(dir|link)?|cv|say|do|name|quire|set|turn|verse|winddir)|rindex|rmdir|s|scalar|seek(dir)?)\\b|\\b(se(lect|mctl|mget|mop|nd|tpgrp|tpriority|tsockopt)|shift|shm(ctl|get|read|write)|shutdown|sin|sleep|socket(pair)?|sort|spli(ce|t)|sprintf|sqrt|srand|stat|study|substr|symlink|sys(call|read|tem|write)|tell(dir)?|time|tr(y)?|truncate|umask)\\b|\\b(un(def|link|pack|shift)|utime|values|vec|wait(pid)?|wantarray|warn|write)\\b" - statement: "\\b(continue|else|elsif|do|for|foreach|if|unless|until|while|eq|ne|lt|gt|le|ge|cmp|x|my|sub|use|package|can|isa)\\b" - special: "\\-\\>" - symbol: "(,|\\.)" #regexes - identifier.macro: "m?\\/.*?\\/[a-z]*" - identifier.macro: "m?\\|.*?\\|[a-z]*" - identifier.macro: "\\bs/.*?/.*?/[a-z]*" - identifier.macro: "\\bs\\|.*?\\|.*?\\|[a-z]*" - constant.string: start: '"' end: '"' skip: '\\"' rules: - identifier.var: '[\\$@%].[a-zA-Z0-9_]*' - constant.string: start: "'" end: "'" skip: "\\\\'" rules: [] - comment: start: "#" end: "$" rules: [] - constant.string: "\"\\(.*\\)\"|qq?\\|.*\\||qq?\\{.*\\}|qq?\\/.*\\/" - constant.number: "\\b([0-9]*[.])?[0-9]+" - constant.number: "\\b[0-9]+" - constant.number: "\\b0x[a-f0-9]+" - constant.string.url: "`(.+?)`" - identifier.var: '[\\$@%].[a-zA-Z0-9_]*' - preproc: start: "(^use| = new)" end: ";" rules: [] - comment: start: "^=" end: "^=cut" rules: [] - identifier.macro: start: "<< 'STOP'" end: "STOP" rules: [] zyedidia-micro-6a62575/runtime/syntax/peg.yaml0000664000175000017510000000074715125206537020723 0ustar nileshnileshfiletype: peg detect: filename: "\\.l?peg$" rules: - identifier: "^[[:space:]]*[A-Za-z][A-Za-z0-9_]*[[:space:]]*<-" - constant.number: "\\^[+-]?[0-9]+" - symbol.operator: "[-+*?^/!&]|->|<-|=>" - identifier.var: "%[A-Za-z][A-Za-z0-9_]*" - special: "\\[[^]]*\\]" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - comment: "(^|[[:space:]])\\-\\-.*$" - todo: "TODO:?" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/patch.yaml0000664000175000017510000000041015125206537021232 0ustar nileshnileshfiletype: patch detect: filename: "\\.(patch|diff)$" header: "^diff" rules: - brightgreen: "^\\+.*" - green: "^\\+\\+\\+.*" - brightblue: "^ .*" - brightred: "^-.*" - red: "^---.*" - brightyellow: "^@@.*" - magenta: "^diff.*" zyedidia-micro-6a62575/runtime/syntax/pascal.yaml0000664000175000017510000000347715125206537021416 0ustar nileshnileshfiletype: pascal detect: filename: "\\.pas$" rules: - type: "\\b(?i:(string|ansistring|widestring|shortstring|char|ansichar|widechar|boolean|byte|shortint|word|smallint|longword|cardinal|longint|integer|int64|single|currency|double|extended))\\b" - statement: "\\b(?i:(and|asm|array|begin|break|case|const|constructor|continue|destructor|div|do|downto|else|end|file|for|function|goto|if|implementation|in|inline|interface|label|mod|not|object|of|on|operator|or|packed|procedure|program|record|repeat|resourcestring|set|shl|shr|then|to|type|unit|until|uses|var|while|with|xor))\\b" - statement: "\\b(?i:(as|class|dispose|except|exit|exports|finalization|finally|inherited|initialization|is|library|new|on|out|property|raise|self|threadvar|try))\\b" - statement: "\\b(?i:(absolute|abstract|alias|assembler|cdecl|cppdecl|default|export|external|forward|generic|index|local|name|nostackframe|oldfpccall|override|pascal|private|protected|public|published|read|register|reintroduce|safecall|softfloat|specialize|stdcall|virtual|write))\\b" - constant: "\\b(?i:(false|true|nil))\\b" - special: start: "asm" end: "end" rules: [] - constant.number: "\\$[0-9A-Fa-f]+" - constant.number: "\\b[+-]?[0-9]+([.]?[0-9]+)?(?i:e[+-]?[0-9]+)?" - constant.string: start: "#[0-9]{1,}" end: "$" rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - preproc: start: "{\\$" end: "}" rules: [] - comment: start: "//" end: "$" rules: [] - comment: start: "\\(\\*" end: "\\*\\)" rules: [] - comment: start: "({)(?:[^$])" end: "}" rules: [] zyedidia-micro-6a62575/runtime/syntax/odin.yaml0000664000175000017510000000441115125206537021071 0ustar nileshnileshfiletype: odin detect: filename: "\\.odin$" rules: # Conditionals and control flow - special: "\\b(asm|auto_cast|break|case|cast|context|continue|do|dynamic|fallthrough|return|transmute|using|where)\\b" - statement: "\\b(else|for|if|switch|in|not_in|or_else|or_return|when)\\b" - preproc: "\\b(assert|package|foreign|import|proc|defer|make|new|free|delete|copy|len|cap|append|raw_data)\\b" - preproc: "\\b((size|align|offset|type|type_info|typeid)_of|offset_of_by_string)\\b" - preproc: "\\b(swizzle|complex|quaternion|real|imag|jmag|kmag|conj|expand_to_tuple|min|max|abs|clamp|soa_zip|soa_unzip|transpose|outer_product|hadamard_product|matrix_flatten)\\b" - symbol.operator: "[-+/*=<>!~%&|^@]|:\\s*=|:\\s*:|\\?" # Types - symbol: "(,|\\.)" - type: "\\b(b(8|16|32|64)|(i|u)(8|(16|32|64|128)(le|be)?)|f(16|32|64)(le|be)?|complex(32|64|128)|quaternion(64|128|256))\\b" - type: "\\b(any|bool|byte|rune|u?int|uintptr|rawptr|c?string|map|matrix|typeid)\\b" - type.keyword: "\\b(distinct|struct|enum|union|bit_set)\\b" - constant.bool: "\\b(true|false|nil)\\b" # Brackets - symbol.brackets: "(\\{|\\})" - symbol.brackets: "(\\(|\\))" - symbol.brackets: "(\\[|\\])" # Numbers and strings - constant.number: "\\b(0b[01]*|0o[0-7]*|0x[0-9a-fA-F]*|[0-9_]+|0d[0-9]*|0z[0-9abAB]*)\\b|'.'" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{1,3}|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - error: "..+" - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{1,3}|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})" - constant.string: start: "`" end: "`" rules: [] - comment: start: "//" end: "$" rules: - todo: "TODO:?|NOTE(\\(.*\\))?:?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "TODO:?|NOTE(\\(.*\\))?:?" zyedidia-micro-6a62575/runtime/syntax/octave.yaml0000664000175000017510000000503215125206537021421 0ustar nileshnilesh# References # https://github.com/zyedidia/micro/blob/master/runtime/syntax/go.yaml # https://github.com/vim-scripts/octave.vim--/blob/master/syntax/octave.vim # # TODO # include only needed operators # ... highlighting # built-in function highlighting? # highlight eps/pi/e etc. as functions when followed by () # what are skip and error fields in strings? # multiline comments not working filetype: octave detect: filename: "\\.m$" rules: # Statements https://www.gnu.org/software/octave/doc/v4.0.0/Statements.html - statement: "\\b(function|endfunction|return|end|global|persistent)\\b" - statement: "\\b(if|elseif|else|endif|switch|case|otherwise|endswitch)\\b" - statement: "\\b(while|endwhile|do|until|for|endfor|parfor|endparfor|break|continue)\\b" - statement: "\\b(unwind_protect|unwind_protect_cleanup|end_unwind_protect|try|catch|end_try_catch)\\b" # Operators - symbol.operator: "[-+/*=<>!~%&|^]|:=" # Brackets - symbol.brackets: "(\\{|\\})" - symbol.brackets: "(\\(|\\))" - symbol.brackets: "(\\[|\\])" # Commas - symbol: "," # Numbers https://www.gnu.org/software/octave/doc/v4.0.1/Mathematical-Constants.html - constant.number: "\\b([0-9]+|0x[0-9a-fA-F]*)\\b|'.'" - constant.number: "\\b(pi|e|I|Inf|NaN|eps|realmax|realmin)\\b|" # Boolean - constant.bool: "\\b(true|false)\\b" # Strings https://www.gnu.org/software/octave/doc/v4.0.1/Strings.html - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "%" - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - error: "..+" - constant.specialChar: "%" - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" # Comments https://www.gnu.org/software/octave/doc/v4.2.1/Comments.html - comment: start: "%" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "%{" end: "%}" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "#{" end: "#}" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/ocaml.yaml0000664000175000017510000000277015125206537021241 0ustar nileshnileshfiletype: ocaml detect: filename: "\\.mli?$" rules: - identifier: "\\b[A-Z][0-9a-z_]{2,}\\b" #declarations - statement: "\\b(let|val|method|in|and|rec|private|virtual|constraint)\\b" #structure items - type: "\\b(type|open|class|module|exception|external)\\b" #patterns - statement: "\\b(fun|function|functor|match|try|with)\\b" #patterns-modifiers - statement: "\\b(as|when|of)\\b" #conditions - statement: "\\b(if|then|else)\\b" #blocs - type: "\\b(begin|end|object|struct|sig|for|while|do|done|to|downto)\\b" - type: "'[0-9A-Za-z_]+" #constantes - constant.bool: "\\b(true|false)\\b" #modules/classes - special: "\\b(include|inherit|initializer)\\b" #expr modifiers - special: "\\b(new|ref|mutable|lazy|assert|raise)\\b" #character literal - constant.string: "'(\\\\[0-7]{3}|\\\\x[A-Fa-f0-9]{2}|\\\\u[A-Fa-f0-9]{4}|\\\\U[A-Fa-f0-9]{8}|\\\\[abfnrtv'\\\"\\\\]|.)'" - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" #string literal - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - comment: start: "\\(\\*" end: "\\*\\)" rules: [] zyedidia-micro-6a62575/runtime/syntax/objc.yaml0000664000175000017510000000501615125206537021057 0ustar nileshnileshfiletype: objective-c detect: filename: "\\.(m|mm|h)$" signature: "(obj|objective)-c|#import|@(encode|end|interface|implementation|selector|protocol|synchronized|try|catch|finally|property|optional|required|import|autoreleasepool)" rules: - type: "\\b(float|double|CGFloat|id|bool|BOOL|Boolean|char|int|short|long|sizeof|enum|void|static|const|struct|union|typedef|extern|(un)?signed|inline|Class|SEL|IMP|NS(U)?Integer)\\b" - type: "\\b((s?size)|((u_?)?int(8|16|32|64|ptr)))_t\\b" - type: "\\b[A-Z][A-Z][[:alnum:]]*\\b" - type: "\\b[A-Za-z0-9_]*_t\\b" - type: "\\bdispatch_[a-zA-Z0-9_]*_t\\b" - statement: "(__attribute__[[:space:]]*\\(\\([^)]*\\)\\)|__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__|__unused|_Nonnull|_Nullable|__block|__builtin.*)" - statement: "\\b(class|namespace|template|public|protected|private|typename|this|friend|virtual|using|mutable|volatile|register|explicit)\\b" - statement: "\\b(for|if|while|do|else|case|default|switch)\\b" - statement: "\\b(try|throw|catch|operator|new|delete)\\b" - statement: "\\b(goto|continue|break|return)\\b" - statement: "\\b(nonatomic|atomic|readonly|readwrite|strong|weak|assign)\\b" - statement: "@(encode|end|interface|implementation|class|selector|protocol|synchronized|try|catch|finally|property|optional|required|import|autoreleasepool)" - preproc: "^[[:space:]]*#[[:space:]]*(define|include|import|(un|ifn?)def|endif|el(if|se)|if|warning|error|pragma).*$" - preproc: "__[A-Z0-9_]*__" - special: "^[[:space:]]*[#|@][[:space:]]*(import|include)[[:space:]]*[\"|<].*\\/?[>|\"][[:space:]]*$" - statement: "([.:;,+*|=!\\%\\[\\]]|<|>|/|-|&)" - constant.number: "(\\b(-?)?[0-9]+\\b|\\b\\[0-9]+\\.[0-9]+\\b|\\b0x[0-9a-fA-F]+\\b)" - constant: "(@\\[(\\\\.|[^\\]])*\\]|@\\{(\\\\.|[^\\}])*\\}|@\\((\\\\.|[^\\)])*\\))" - constant: "\\b<(\\\\.[^\\>])*\\>\\b" - constant: "\\b(nil|NULL|YES|NO|TRUE|true|FALSE|false|self)\\b" - constant: "\\bk[[:alnum]]*\\b" - constant.string: "'.'" - constant.string: start: "@\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/nu.yaml0000664000175000017510000001552315125206537020570 0ustar nileshnileshfiletype: nu detect: filename: "\\.nu$" rules: - symbol: "[-+/*=<>!~%?:&|]" # https://www.nushell.sh/book/command_reference.html - statement: "\\b(agg-groups|agg|alias|all-false|all-true|all?|ansi gradient)\\b" - statement: "\\b(ansi strip|ansi|any?|append|append|arg-max)\\b" - statement: "\\b(arg-min|arg-sort|arg-true|arg-unique|as-date)\\b" - statement: "\\b(as-datetime|as|benchmark|build-string|cache|cal|cd)\\b" - statement: "\\b(char|clear|col|collect|columns|compact|complete)\\b" - statement: "\\b(concatenate|config|config env|config nu|contains)\\b" - statement: "\\b(count|count-null|cp|cumulative|date format|date humanize)\\b" - statement: "\\b(date list-timezone|date now|date to-record|date to-table)\\b" - statement: "\\b(date to-timezone|date|db and|db as|db col|db collect)\\b" - statement: "\\b(db describe|db fn|db from|db group-by|db join|db limit)\\b" - statement: "\\b(db open|db or|db order-by|db over|db query|db schema)\\b" - statement: "\\b(db select|db testing|db where|db|debug|decode)\\b" - statement: "\\b(def-env|default|def|describe|describe|detect columns)\\b" - statement: "\\b(df-not|do|drop|drop|drop column|drop nth|drop-duplicates)\\b" - statement: "\\b(drop-nulls|dtypes|du|each while|each|echo|empty?)\\b" - statement: "\\b(enter|env|error make|every|exec|exit|explode)\\b" - statement: "\\b(export alias|export def|export def-env|export env)\\b" - statement: "\\b(export extern|export|expr-not|extern|fetch|fill-na)\\b" - statement: "\\b(fill-null|filter-with|find|first|flatten)\\b" - statement: "\\b(fmt|format filesize|format|for|from csv|from eml)\\b" - statement: "\\b(from ics|from ini|from json|from nuon|from ods|from ssv)\\b" - statement: "\\b(from toml|from tsv|from url|from vcf|from xlsx|from xml)\\b" - statement: "\\b(from yaml|from yml|from|get-day|get-hour|get-minute)\\b" - statement: "\\b(get-month|get-nanosecond|get-ordinal|get-second|get-week)\\b" - statement: "\\b(get-weekday|get-year|get|glob|grid|group-by)\\b" - statement: "\\b(group|gstat|g|hash base64|hash md5|hash sha256|hash)\\b" - statement: "\\b(headers|help|hide|histogram|history|if|ignore)\\b" - statement: "\\b(inc|input|insert|into binary|into bool|into datetime|into decimal)\\b" - statement: "\\b(into duration|into filesize|into int|into string|into)\\b" - statement: "\\b(is-admin|is-duplicated|is-in|is-not-null)\\b" - statement: "\\b(is-null|is-unique|join|keep|keep until)\\b" - statement: "\\b(keep while|keybindings default|keybindings listen|keybindings list)\\b" - statement: "\\b(keybindings|kill|last|length|let-env|let)\\b" - statement: "\\b(lines|list|lit|load-env|ls|ls-df|match|math abs)\\b" - statement: "\\b(math avg|math ceil|math eval|math floor|math max)\\b" - statement: "\\b(math median|math min|math mode|math product|math round)\\b" - statement: "\\b(math sqrt|math stddev|math sum|math variance|math|max)\\b" - statement: "\\b(mean|median|melt|merge|metadata)\\b" - statement: "\\b(min|mkdir|module|move|mv|n|n-unique|n-unique)\\b" - statement: "\\b(nth|nu-highlight|open|open-df|otherwise|overlay)\\b" - statement: "\\b(overlay add|overlay list|overlay new|overlay remove|p)\\b" - statement: "\\b(par-each|parse|path basename|path dirname|path exists)\\b" - statement: "\\b(path expand|path join|path parse|path relative-to|path split)\\b" - statement: "\\b(path type|path|pivot|post|prepend|print|ps|quantile)\\b" - statement: "\\b(quantile|query json|query web|query xml|query|random bool)\\b" - statement: "\\b(random chars|random decimal|random dice|random integer)\\b" - statement: "\\b(random uuid|random|range|reduce|register|reject|rename)\\b" - statement: "\\b(replace|replace-all|reverse|reverse|rm|roll down)\\b" - statement: "\\b(roll left|roll right|roll up|rolling|roll|rotate)\\b" - statement: "\\b(run-external|sample|save|select|select|seq|seq char)\\b" - statement: "\\b(seq date|set|set-with-idx|shape|shells|shift|shuffle)\\b" - statement: "\\b(size|skip until|skip while|skip|sleep|slice|sort)\\b" - statement: "\\b(sort-by|source|split chars|split column|split row)\\b" - statement: "\\b(split-by|split|std|std|str camel-case|str capitalize)\\b" - statement: "\\b(str collect|str contains|str downcase|str ends-with|str find-replace)\\b" - statement: "\\b(str index-of|str kebab-case|str length|str lpad|str pascal-case)\\b" - statement: "\\b(str replace|str reverse|str rpad|str screaming-snake-case)\\b" - statement: "\\b(str snake-case|str starts-with|str substring|str title-case)\\b" - statement: "\\b(str to-datetime|str to-decimal|str to-int|str trim|str upcase)\\b" - statement: "\\b(str-lengths|str-slice|strftime|str|sum|sys|table)\\b" - statement: "\\b(take until|take while|take|term size|to csv)\\b" - statement: "\\b(to html|to json|to md|to nuon|to text|to toml|to tsv)\\b" - statement: "\\b(to url|to xml|to yaml|to-csv|to-df|to-dummies|to-lazy)\\b" - statement: "\\b(to-lowercase|to-nu|to-parquet|to-uppercase|touch|to)\\b" - statement: "\\b(transpose|tutor|unalias|uniq|unique|update|update cells)\\b" - statement: "\\b(upsert|url host|url path|url query|url scheme|url)\\b" - statement: "\\b(use|value-counts|var|version|view-source|watch)\\b" - statement: "\\b(when|where|which|window|with-column|with-env|wrap)\\b" # https://www.nushell.sh/book/types_of_data.html#booleans - constant: "\\b(false|true)\\b" - constant.number: "\\b[-+]?([1-9][0-9])*\\b" # https://www.nushell.sh/book/types_of_data.html#binary-data - constant.number: "\\b[-+]?(0(x|b|o)\\[[0-9a-fA-F ]+\\])" # https://www.nushell.sh/book/types_of_data.html#file-sizes - constant.number: "\\b[-+]?([0-9]+[BbMmGgTtPp][i]?[Bb]?)?\\b" # https://www.nushell.sh/book/types_of_data.html#duration - constant.number: "\\b[-+]?([0-9]+[num]?[s])?\\b" - constant.number: "\\b[-+]?([0-9]+(sec|min|hr|day|wk))?\\b" # https://www.nushell.sh/book/types_of_data.html#dates - constant.number: "\\b([0-9]+[-][0-9]+[-][0-9]+([T][0-9]+[:][0-9]+[:][0-9]+)?([\\+][0-9]+[:][0-9]+)?)\\b" # https://www.nushell.sh/book/types_of_data.html#ranges - constant.number: "([0-9]+(\\.\\.)[0-9]+)?" # https://www.nushell.sh/book/types_of_data.html#open-ended-ranges - constant.number: "((\\.\\.)[0-9]+)?" - constant.number: "([0-9]+(\\.\\.))?" - comment: start: "#" end: "$" rules: [] - comment: start: "/\\*" end: "\\*/" rules: - todo: "(FIXME|TODO|NOTE):?" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." zyedidia-micro-6a62575/runtime/syntax/nix.yaml0000664000175000017510000000124215125206537020735 0ustar nileshnileshfiletype: nix detect: filename: "\\.nix$" rules: - special: "\\b(Ellipsis|null|self|super|true|false|abort)\\b" - statement: "\\b(let|in|with|import|rec|inherit)\\b" - symbol.operator: "([~^.:;,+*|=!\\%@]|<|>|/|-|&)" - symbol.brackets: "([(){}]|\\[|\\])" - constant.number: "\\b[0-9](_?[0-9])*(\\.([0-9](_?[0-9])*)?)?(e[0-9](_?[0-9])*)?\\b" - constant.string: start: "\"" end: "\"" rules: [] - constant.string: start: "''" end: "''" rules: [] - comment: start: "#" end: "$" rules: [] - comment: start: "/\\*" end: "\\*/" rules: [] zyedidia-micro-6a62575/runtime/syntax/nim.yaml0000664000175000017510000000451615125206537020731 0ustar nileshnileshfiletype: nim detect: filename: "\\.nims?$|nim.cfg" rules: - preproc: "[\\{\\|]\\b(atom|lit|sym|ident|call|lvalue|sideeffect|nosideeffect|param|genericparam|module|type|let|var|const|result|proc|method|iterator|converter|macro|template|field|enumfield|forvar|label|nk[a-zA-Z]+|alias|noalias)\\b[\\}\\|]" - statement: "\\b(addr|and|as|asm|atomic|bind|block|break|case|cast|concept|const|continue|converter|defer|discard|distinct|div|do|elif|else|end|enum|except|export|finally|for|from|func|generic|if|import|in|include|interface|is|isnot|iterator|let|macro|method|mixin|mod|nil|not|notin|object|of|or|out|proc|ptr|raise|ref|return|shl|shr|static|template|try|tuple|type|using|var|when|while|with|without|xor|yield)\\b" - statement: "\\b(deprecated|noSideEffect|constructor|destructor|override|procvar|compileTime|noReturn|acyclic|final|shallow|pure|asmNoStackFrame|error|fatal|warning|hint|line|linearScanEnd|computedGoto|unroll|immediate|checks|boundsChecks|overflowChecks|nilChecks|assertations|warnings|hints|optimization|patterns|callconv|push|pop|global|pragma|experimental|bitsize|volatile|noDecl|header|incompleteStruct|compile|link|passC|passL|emit|importc|importcpp|importobjc|codegenDecl|injectStmt|intdefine|strdefine|varargs|exportc|extern|bycopy|byref|union|packed|unchecked|dynlib|cdecl|thread|gcsafe|threadvar|guard|locks|compileTime)\\b" - symbol.operator: "[=\\+\\-\\*/<>@\\$~&%\\|!\\?\\^\\.:\\\\]+" - special: "\\{\\.|\\.\\}|\\[\\.|\\.\\]|\\(\\.|\\.\\)|;|,|`" - statement: "\\.\\." - type: "\\b(int|cint|int8|int16|int32|int64|uint|uint8|uint16|uint32|uint64|float|float32|float64|bool|char|enum|string|cstring|cstringArray|cdouble|csize_t|pointer|array|openarray|seq|varargs|tuple|object|set|void|auto|cshort|clong|range|nil|T|untyped|typedesc)\\b" - type: "'[iI](8|16|32|64)?\\b|'[uU](8|16|32|64)?\\b|'[fF](32|64|128)?\\b|'[dD]\\b" - constant.number: "\\b[0-9]+\\b" - constant.number: "\\b0[xX][0-9A-Fa-f][0-9_A-Fa-f]+\\b" - constant.number: "\\b0[ocC][0-7][0-7_]+\\b" - constant.number: "\\b0[bB][01][01_]+\\b" - constant.number: "\\b[0-9_]((\\.?)[0-9_]+)?[eE][+\\-][0-9][0-9_]+\\b" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - comment: "[[:space:]]*(?:[^\\\\]|^)#.*$" - comment: start: "\\#\\[" end: "\\]\\#" rules: [] - todo: "(TODO|FIXME|XXX):?" zyedidia-micro-6a62575/runtime/syntax/nginx.yaml0000664000175000017510000001163315125206537021267 0ustar nileshnileshfiletype: nginx detect: filename: "nginx.*\\.conf$|\\.nginx$" header: "^(server|upstream)[a-z ]*\\{$" rules: - preproc: "\\b(events|server|http|location|upstream)[[:space:]]*\\{" - statement: "(^|[[:space:]{;])(access_log|add_after_body|add_before_body|add_header|addition_types|aio|alias|allow|ancient_browser|ancient_browser_value|auth_basic|auth_basic_user_file|autoindex|autoindex_exact_size|autoindex_localtime|break|charset|charset_map|charset_types|chunked_transfer_encoding|client_body_buffer_size|client_body_in_file_only|client_body_in_single_buffer|client_body_temp_path|client_body_timeout|client_header_buffer_size|client_header_timeout|client_max_body_size|connection_pool_size|create_full_put_path|daemon|dav_access|dav_methods|default_type|deny|directio|directio_alignment|disable_symlinks|empty_gif|env|error_log|error_page|expires|fastcgi_buffer_size|fastcgi_buffers|fastcgi_busy_buffers_size|fastcgi_cache|fastcgi_cache_bypass|fastcgi_cache_key|fastcgi_cache_lock|fastcgi_cache_lock_timeout|fastcgi_cache_min_uses|fastcgi_cache_path|fastcgi_cache_use_stale|fastcgi_cache_valid|fastcgi_connect_timeout|fastcgi_hide_header|fastcgi_ignore_client_abort|fastcgi_ignore_headers|fastcgi_index|fastcgi_intercept_errors|fastcgi_keep_conn|fastcgi_max_temp_file_size|fastcgi_next_upstream|fastcgi_no_cache|fastcgi_param|fastcgi_pass|fastcgi_pass_header|fastcgi_read_timeout|fastcgi_send_timeout|fastcgi_split_path_info|fastcgi_store|fastcgi_store_access|fastcgi_temp_file_write_size|fastcgi_temp_path|flv|geo|geoip_city|geoip_country|gzip|gzip_buffers|gzip_comp_level|gzip_disable|gzip_http_version|gzip_min_length|gzip_proxied|gzip_static|gzip_types|gzip_vary|if|if_modified_since|ignore_invalid_headers|image_filter|image_filter_buffer|image_filter_jpeg_quality|image_filter_sharpen|image_filter_transparency|include|index|internal|ip_hash|keepalive|keepalive_disable|keepalive_requests|keepalive_timeout|large_client_header_buffers|limit_conn|limit_conn_log_level|limit_conn_zone|limit_except|limit_rate|limit_rate_after|limit_req|limit_req_log_level|limit_req_zone|limit_zone|lingering_close|lingering_time|lingering_timeout|listen|location|log_format|log_not_found|log_subrequest|map|map_hash_bucket_size|map_hash_max_size|master_process|max_ranges|memcached_buffer_size|memcached_connect_timeout|memcached_next_upstream|memcached_pass|memcached_read_timeout|memcached_send_timeout|merge_slashes|min_delete_depth|modern_browser|modern_browser_value|mp4|mp4_buffer_size|mp4_max_buffer_size|msie_padding|msie_refresh|open_file_cache|open_file_cache_errors|open_file_cache_min_uses|open_file_cache_valid|open_log_file_cache|optimize_server_names|override_charset|pcre_jit|perl|perl_modules|perl_require|perl_set|pid|port_in_redirect|postpone_output|proxy_buffer_size|proxy_buffering|proxy_buffers|proxy_busy_buffers_size|proxy_cache|proxy_cache_bypass|proxy_cache_key|proxy_cache_lock|proxy_cache_lock_timeout|proxy_cache_min_uses|proxy_cache_path|proxy_cache_use_stale|proxy_cache_valid|proxy_connect_timeout|proxy_cookie_domain|proxy_cookie_path|proxy_hide_header|proxy_http_version|proxy_ignore_client_abort|proxy_ignore_headers|proxy_intercept_errors|proxy_max_temp_file_size|proxy_next_upstream|proxy_no_cache|proxy_pass|proxy_pass_header|proxy_read_timeout|proxy_redirect|proxy_send_timeout|proxy_set_header|proxy_ssl_session_reuse|proxy_store|proxy_store_access|proxy_temp_file_write_size|proxy_temp_path|random_index|read_ahead|real_ip_header|recursive_error_pages|request_pool_size|reset_timedout_connection|resolver|resolver_timeout|return|rewrite|root|satisfy|satisfy_any|secure_link_secret|send_lowat|send_timeout|sendfile|sendfile_max_chunk|server|server|server_name|server_name_in_redirect|server_names_hash_bucket_size|server_names_hash_max_size|server_tokens|set|set_real_ip_from|source_charset|split_clients|ssi|ssi_silent_errors|ssi_types|ssl|ssl_certificate|ssl_certificate_key|ssl_ciphers|ssl_client_certificate|ssl_crl|ssl_dhparam|ssl_engine|ssl_prefer_server_ciphers|ssl_protocols|ssl_session_cache|ssl_session_timeout|ssl_verify_client|ssl_verify_depth|sub_filter|sub_filter_once|sub_filter_types|tcp_nodelay|tcp_nopush|timer_resolution|try_files|types|types_hash_bucket_size|types_hash_max_size|underscores_in_headers|uninitialized_variable_warn|upstream|user|userid|userid_domain|userid_expires|userid_name|userid_p3p|userid_path|userid_service|valid_referers|variables_hash_bucket_size|variables_hash_max_size|worker_priority|worker_processes|worker_rlimit_core|worker_rlimit_nofile|working_directory|xml_entities|xslt_stylesheet|xslt_types)([[:space:]]|$)" - constant.bool.true: "\\b(on)\\b" - constant.bool.false: "\\b(off)\\b" - identifier: "\\$[A-Za-z][A-Za-z0-9_]*" - symbol: "[*]" - constant-string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - constant.string: start: "'$" end: "';$" rules: [] - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/nftables.yaml0000664000175000017510000000216515125206537021742 0ustar nileshnileshfiletype: nftables detect: filename: "(nftables\\.(conf|rules)$|nftables(\\.rules)?\\.d/)" header: "^(#!.*/(env +)?nft( |$)|flush +ruleset)" rules: - type: "\\b(chain|counter|map|rule|ruleset|set|table)\\b" - type: "\\b(ether|inet|i(cm)?p(x|(v?(4|6))?)|tcp|udp|8021q)\\b" - special: "\\b(element(s)?|hook|policy|priority|type|state)\\b" - identifier: "\\b(ct|iif|iifname|meta|oif|oifname|th|dport|sport|saddr|daddr|l4proto)\\b" - statement: "\\b(accept|drop|goto|jump|log|masquerade|reject|limit|queue)\\b" - preproc: "\\b(add|define|flush|include|delete)\\b" - symbol.operator: "[<>.&|^!=:;,@]|\\b(and|ge|gt|le|lt|or|xor)\\b" - constant.string: start: "\"" end: "\"" rules: [] # Integer Constants - constant.number: "\\b([0-9]+)\\b" - constant.number: "\\b(0x[0-9a-fA-F]+)\\b" - identifier.var: "[$@][a-zA-Z_.][a-zA-Z0-9_/.-]*" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" - comment: start: "#" end: "$" rules: - todo: "(TODO|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/nanorc.yaml0000664000175000017510000000212015125206537021413 0ustar nileshnileshfiletype: nanorc detect: filename: "\\.?nanorc$" rules: - default: "(?i)^[[:space:]]*((un)?set|include|syntax|i?color).*$" - type: "(?i)^[[:space:]]*(set|unset)[[:space:]]+(autoindent|backup|backupdir|backwards|boldtext|brackets|casesensitive|const|cut|fill|historylog|matchbrackets|morespace|mouse|multibuffer|noconvert|nofollow|nohelp|nonewlines|nowrap|operatingdir|preserve|punct)\\>|^[[:space:]]*(set|unset)[[:space:]]+(quickblank|quotestr|rebinddelete|rebindkeypad|regexp|smarthome|smooth|speller|suspend|tabsize|tabstospaces|tempfile|undo|view|whitespace|wordbounds)\\b" - preproc: "(?i)^[[:space:]]*(set|unset|include|syntax|header)\\b" - constant.bool.true: "(?i)(set)\\b" - constant.bool.false: "(?i)(unset)\\b" - identifier: "(?i)^[[:space:]]*(i)?color[[:space:]]*(bright)?(white|black|red|blue|green|yellow|magenta|cyan)?(,(white|black|red|blue|green|yellow|magenta|cyan))?\\b" - special: "(?i)^[[:space:]]*(i)?color\\b|\\b(start|end)=" - constant.string: "\"(\\\\.|[^\"])*\"" - comment: "^[[:space:]]*#.*$" - comment.bright: "^[[:space:]]*##.*$" zyedidia-micro-6a62575/runtime/syntax/msbuild.yaml0000664000175000017510000000015015125206537021573 0ustar nileshnileshfiletype: msbuild detect: filename: "\\.(.*proj|props|targets|tasks)$" rules: - include: "xml" zyedidia-micro-6a62575/runtime/syntax/mpdconf.yaml0000664000175000017510000000073115125206537021567 0ustar nileshnileshfiletype: mpd detect: filename: "mpd\\.conf$" rules: - statement: "\\b(user|group|bind_to_address|host|port|plugin|name|type)\\b" - statement: "\\b((music|playlist)_directory|(db|log|state|pid|sticker)_file)\\b" - special: "^(input|audio_output|decoder)[[:space:]]*\\{|\\}" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/micro.yaml0000664000175000017510000000243215125206537021252 0ustar nileshnileshfiletype: micro detect: filename: "\\.(micro)$" rules: - statement: "\\b(syntax|color(-link)?)\\b" - statement: "\\b(start=|end=)\\b" # Simple one-liners - identifier: "\\b(default|number|statement|underlined|error|todo|statusline|indent-char|cursor\\-line|color\\-column|ignore|divider|tabbar)\\b" # Separate identifiers to keep "complex" regex clean - identifier: "\\b(special(Char)?)\\b" - identifier: "\\b((current\\-)?line\\-number)\\b" - identifier: "\\b(gutter\\-(info|error|warning){1})\\b" - identifier: "\\b(comment(\\.bright)?)\\b" - identifier: "\\b(symbol(\\.(brackets|operator|tag))?)\\b" - identifier: "\\b(identifier(\\.(class|macro|var))?)\\b" - identifier: "\\b(constant(\\.(bool(\\.(true|false){1})?|number|specialChar|string(\\.url)?){1})?)\\b" - identifier: "\\b(preproc(\\.shebang)?)\\b" - identifier: "\\b(type(\\.keyword)?)\\b" - constant.number: "\\b(|h|A|0x)+[0-9]+(|h|A)+\\b" - constant.number: "\\b0x[0-9 a-f A-F]+\\b" - comment: start: "#" end: "$" rules: - todo: "(FIXME|TODO|NOTE):?" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.number: "#[0-9 A-F a-f]+" zyedidia-micro-6a62575/runtime/syntax/meson.yaml0000775000175000017510000000417315125206537021271 0ustar nileshnileshfiletype: meson detect: filename: "(meson\\.build|meson_options\\.txt|meson\\.options)" rules: # refer to https://mesonbuild.com/Syntax.html - statement: "\\b(elif|else|if|endif)\\b" - statement: "\\b(foreach|endforeach)\\b" - statement: "\\b(continue|break)\\b" - statement: "\\b(and|not|or|in)\\b" - symbol.operator: "[<>?:+*/-]|[+!<>=]?=" - symbol.brackets: "[(){}\\[\\]]" - constant.number: "\\b(0|[1-9][0-9]*)\\b" # decimal - constant.number: "\\b(0b[01]+)\\b" # bin - constant.number: "\\b(0o[0-7]+)\\b" # oct - constant.number: "\\b(0x[0-9a-fA-F]+)\\b" # hex # meson builtins - identifier: "\\b(add_global_arguments|add_global_link_arguments|add_languages|add_project_arguments|add_project_dependencies)\\b" - identifier: "\\b(add_project_link_arguments|add_test_setup|alias_target|assert|benchmark|both_libraries|build_machine|build_target|configuration_data)\\b" - identifier: "\\b(configure_file|custom_target|debug|declare_dependency|dependency|disabler|environment|error|executable|files)\\b" - identifier: "\\b(find_program|generator|get_option|get_variable|host_machine|import|include_directories|install_data|install_emptydir)\\b" - identifier: "\\b(install_headers|install_man|install_subdir|install_symlink|is_disabler|is_variable|jar|join_paths|library|meson)\\b" - identifier: "\\b(message|option|project|range|run_command|run_target|set_variable|shared_library|shared_module|static_library)\\b" - identifier: "\\b(structured_sources|subdir|subdir_done|subproject|summary|target_machine|test|unset_variable|vcs_tag|warning)\\b" - constant.bool: "\\b(true|false)\\b" - comment: start: "#" end: "$" rules: [] # multiline strings do not support escape sequences - constant.string: start: "'''" end: "'''" rules: [] - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\[abfnrtv\\\\']" - constant.specialChar: "\\\\([0-7]{1,3}|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|N\\{[^\\}]+\\})" zyedidia-micro-6a62575/runtime/syntax/mc.yaml0000664000175000017510000000063015125206537020536 0ustar nileshnilesh# sendmail config files filetype: mc detect: filename: "\\.mc$" rules: - statement: "^(divert|VERSIONID|OSTYPE|DOMAIN|FEATURE|define)" - statement: "^(DAEMON_OPTIONS|MAILER)" - comment: start: "#" end: "$" rules: [] - comment: start: "dnl" end: "$" rules: [] - constant.string: start: "`" end: "'" rules: [] zyedidia-micro-6a62575/runtime/syntax/markdown.yaml0000664000175000017510000000204015125206537021756 0ustar nileshnileshfiletype: markdown detect: filename: "\\.(livemd|md|mkd|mkdn|markdown)$" rules: # Tables (Github extension) - type: ".*[ :]\\|[ :].*" # quotes - statement: "^>.*" # Emphasis - type: "(^|[[:space:]])(_[^ ][^_]*_|\\*[^ ][^*]*\\*)" # Strong emphasis - type: "(^|[[:space:]])(__[^ ][^_]*__|\\*\\*[^ ][^*]*\\*\\*)" # strike-through - type: "(^|[[:space:]])~~[^ ][^~]*~~" # horizontal rules - special: "^(---+|===+|___+|\\*\\*\\*+)\\s*$" # headlines - special: "^#{1,6}.*" # lists - identifier: "^[[:space:]]*[\\*+-] |^[[:space:]]*[0-9]+\\. " # misc - preproc: "(\\(([CcRr]|[Tt][Mm])\\)|\\.{3}|(^|[[:space:]])\\-\\-($|[[:space:]]))" # links - constant: "\\[[^]]+\\]" - constant: "\\[([^][]|\\[[^]]*\\])*\\]\\([^)]+\\)" # images - underlined: "!\\[[^][]*\\](\\([^)]+\\)|\\[[^]]+\\])" # urls - underlined: "https?://[^ )>]+" - special: "^```$" - special: start: "`" end: "`" rules: [] zyedidia-micro-6a62575/runtime/syntax/man.yaml0000664000175000017510000000041615125206537020714 0ustar nileshnileshfiletype: man detect: filename: "\\.[1-9]x?$" rules: - green: "\\.(S|T)H.*$" - brightgreen: "\\.(S|T)H|\\.TP" - brightred: "\\.(BR?|I[PR]?).*$" - brightblue: "\\.(BR?|I[PR]?|PP)" - brightwhite: "\\\\f[BIPR]" - yellow: "\\.(br|DS|RS|RE|PD)" zyedidia-micro-6a62575/runtime/syntax/makefile.yaml0000664000175000017510000000241615125206537021720 0ustar nileshnileshfiletype: makefile detect: filename: "([Mm]akefile|\\.ma?k)$" header: "^#!.*/(env +)?[bg]?make( |$)" rules: - preproc: "\\<(ifeq|ifdef|ifneq|ifndef|else|endif)\\>" - statement: "^(export|include|override)\\>" - symbol.operator: "^[^:= ]+:" - symbol.operator: "([=,%]|\\+=|\\?=|:=|&&|\\|\\|)" - statement: "\\$\\((abspath|addprefix|addsuffix|and|basename|call|dir)[[:space:]]" - statement: "\\$\\((error|eval|filter|filter-out|findstring|firstword)[[:space:]]" - statement: "\\$\\((flavor|foreach|if|info|join|lastword|notdir|or)[[:space:]]" - statement: "\\$\\((origin|patsubst|realpath|shell|sort|strip|suffix)[[:space:]]" - statement: "\\$\\((value|warning|wildcard|word|wordlist|words)[[:space:]]" - identifier: "^.+:" - identifier: "[()$]" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - identifier: "\\$+(\\{[^} ]+\\}|\\([^) ]+\\))" - identifier: "\\$[@^<*?%|+]|\\$\\([@^<*?%+-][DF]\\)" - identifier: "\\$\\$|\\\\.?" - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/make_headers.go0000664000175000017510000000275015125206537022217 0ustar nileshnilesh//go:build ignore // +build ignore package main import ( "bytes" "fmt" "os" "strings" "time" yaml "gopkg.in/yaml.v2" ) type HeaderYaml struct { FileType string `yaml:"filetype"` Detect struct { FNameRgx string `yaml:"filename"` HeaderRgx string `yaml:"header"` SignatureRgx string `yaml:"signature"` } `yaml:"detect"` } type Header struct { FileType string FNameRgx string HeaderRgx string SignatureRgx string } func main() { if len(os.Args) > 1 { os.Chdir(os.Args[1]) } files, _ := os.ReadDir(".") for _, f := range files { fname := f.Name() if strings.HasSuffix(fname, ".yaml") { convert(fname[:len(fname)-5]) } } } func convert(name string) { filename := name + ".yaml" var hdr HeaderYaml source, err := os.ReadFile(filename) if err != nil { panic(err) } err = yaml.Unmarshal(source, &hdr) if err != nil { panic(err) } encode(name, hdr) } func encode(name string, c HeaderYaml) { f, _ := os.Create(name + ".hdr") f.WriteString(c.FileType + "\n") f.WriteString(c.Detect.FNameRgx + "\n") f.WriteString(c.Detect.HeaderRgx + "\n") f.WriteString(c.Detect.SignatureRgx + "\n") f.Close() } func decode(name string) Header { start := time.Now() data, _ := os.ReadFile(name + ".hdr") strs := bytes.Split(data, []byte{'\n'}) var hdr Header hdr.FileType = string(strs[0]) hdr.FNameRgx = string(strs[1]) hdr.HeaderRgx = string(strs[2]) hdr.SignatureRgx = string(strs[3]) fmt.Printf("took %v\n", time.Since(start)) return hdr } zyedidia-micro-6a62575/runtime/syntax/mail.yaml0000664000175000017510000000112615125206537021062 0ustar nileshnileshfiletype: mail detect: filename: "(.*/mutt-.*|\\.eml)$" header: "^From .* \\d+:\\d+:\\d+ \\d+" rules: - type: "^From .*" - identifier: "^[^[:space:]]+:" - preproc: "^List-(Id|Archive|Subscribe|Unsubscribe|Post|Help):" - constant: "^(To|From):" - constant.string: start: "^Subject:.*" end: "$" rules: - constant.specialChar: "\\\\." - statement: "?" - default: start: "^\\n\\n" end: ".*" rules: [] - comment: start: "^>.*" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/lua.yaml0000664000175000017510000001031415125206537020720 0ustar nileshnileshfiletype: lua detect: filename: "\\.lua$" rules: - statement: "\\b(do|end|while|break|repeat|until|if|elseif|then|else|for|in|function|local|return|goto)\\b" - statement: "\\b(not|and|or)\\b" - statement: "\\b(debug|string|math|table|io|coroutine|os|utf8|bit32)\\b\\." - statement: "\\b(_ENV|_G|_VERSION|assert|collectgarbage|dofile|error|getfenv|getmetatable|ipairs|load|loadfile|module|next|pairs|pcall|print|rawequal|rawget|rawlen|rawset|require|select|setfenv|setmetatable|tonumber|tostring|type|unpack|xpcall)\\s*\\(" - identifier: "io\\.\\b(close|flush|input|lines|open|output|popen|read|tmpfile|type|write)\\b" - identifier: "math\\.\\b(abs|acos|asin|atan2|atan|ceil|cosh|cos|deg|exp|floor|fmod|frexp|huge|ldexp|log10|log|max|maxinteger|min|mininteger|modf|pi|pow|rad|random|randomseed|sin|sqrt|tan|tointeger|type|ult)\\b" - identifier: "os\\.\\b(clock|date|difftime|execute|exit|getenv|remove|rename|setlocale|time|tmpname)\\b" - identifier: "package\\.\\b(config|cpath|loaded|loadlib|path|preload|seeall|searchers|searchpath)\\b" - identifier: "string\\.\\b(byte|char|dump|find|format|gmatch|gsub|len|lower|match|pack|packsize|rep|reverse|sub|unpack|upper)\\b" - identifier: "table\\.\\b(concat|insert|maxn|move|pack|remove|sort|unpack)\\b" - identifier: "utf8\\.\\b(char|charpattern|codes|codepoint|len|offset)\\b" - identifier: "coroutine\\.\\b(create|isyieldable|resume|running|status|wrap|yield)\\b" - identifier: "debug\\.\\b(debug|getfenv|gethook|getinfo|getlocal|getmetatable|getregistry|getupvalue|getuservalue|setfenv|sethook|setlocal|setmetatable|setupvalue|setuservalue|traceback|upvalueid|upvaluejoin)\\b" - identifier: "bit32\\.\\b(arshift|band|bnot|bor|btest|bxor|extract|replace|lrotate|lshift|rrotate|rshift)\\b" - identifier: "\\:\\b(close|flush|lines|read|seek|setvbuf|write|byte|char|dump|find|format|gmatch|gsub|len|lower|match|pack|packsize|rep|reverse|sub|unpack|upper)\\b" - identifier: "\\b(self|arg)\\b" - constant: "\\b(false|nil|true)\\b" - statement: "(\\b(dofile|require|include)|%q|%!|%Q|%r|%x)\\b" - symbol.brackets: "[(){}\\[\\]]" - symbol: "(\\*|//|/|%|\\+|-|\\^|>|>=|<|<=|~=|=|[\\.]{2,3}|#)" - constant.number: "\\b((0[xX](([0-9A-Fa-f]+\\.[0-9A-Fa-f]*)|(\\.?[0-9A-Fa-f]+))([pP][-+]?[0-9]+)?)|((([0-9]+\\.[0-9]*)|(\\.?[0-9]+))([eE][-+]?[0-9]+)?))" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([abfnrtvz\\'\"]|[0-9]{1,3}|x[0-9a-fA-F][0-9a-fA-F]|u\\{[0-9a-fA-F]+\\})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\([abfnrtvz\\'\"]|[0-9]{1,3}|x[0-9a-fA-F][0-9a-fA-F]|u\\{[0-9a-fA-F]+\\})" - constant.string: start: "\\[\\[" end: "\\]\\]" rules: [] # support first few lengths of "long brackets" explicitly # brackets longer than that will give false positives - constant.string: start: "\\[=\\[" end: "\\]=\\]" rules: [] - constant.string: start: "\\[==\\[" end: "\\]==\\]" rules: [] - constant.string: start: "\\[===\\[" end: "\\]===\\]" rules: [] - constant.string: start: "\\[====+\\[" end: "\\]====+\\]" rules: [] - comment.block: start: "\\-\\-\\[\\[" end: "\\]\\]" rules: - todo: "(TODO|NOTE|FIXME):?" # support long brackets, same as with multiline strings - comment.block: start: "\\-\\-\\[=\\[" end: "\\]=\\]" rules: - todo: "(TODO|NOTE|FIXME):?" - comment.block: start: "\\-\\-\\[==\\[" end: "\\]==\\]" rules: - todo: "(TODO|NOTE|FIXME):?" - comment.block: start: "\\-\\-\\[===\\[" end: "\\]===\\]" rules: - todo: "(TODO|NOTE|FIXME):?" - comment.block: start: "\\-\\-\\[====+\\[" end: "\\]====+\\]" rules: - todo: "(TODO|NOTE|FIXME):?" # this has to go after block comment or block comment does not work - comment: start: "\\-\\-" end: "$" rules: - todo: "(TODO|NOTE|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/log.yaml0000664000175000017510000000737315125206537020733 0ustar nileshnileshfiletype: log detect: filename: "(\\.log|log\\.txt)$" rules: - diff-modified: "\\b(WARN(ING)?|[Ww]arn(ing)?|w(r)?n|w|W/)\\b" - diff-modified: "\\b(CRITICAL|[Cc]ritical)\\b" - constant: "\\b(INFO(RMATION)?|[Ii]nfo(rmation)?|[Ii]n(f)?|i|I/)\\b" - constant: "\\b(DEBUG|[Dd]ebug|dbug|dbg|de|d|D/)\\b" - constant: "\\b(VERBOSE|[Vv]erbose|V/)\\b" - constant: "\\b(ALERT|[Aa]lert)\\b" - preproc: "\\b(TRACE|Trace|NOTICE|VERBOSE|verb|vrb|vb|v)\\b" - gutter-error: "\\b(ERROR|[Ee]rr(or)?|[Ee]r(or)?|e|E\\x2F)\\b" - gutter-error: "\\b(FATAL|[Ff]atal)\\b" - gutter-error: "\\b(EMERGENCY|[Ee]mergency)\\b" - gutter-error: "\\b(FAIL(URE)?|[Ff]ail(ure)?)\\b" # constants - constant.bool.true: "\\b(YES|yes|Y|y|ON|on|TRUE|True|true)\\b" - constant.bool.false: "\\b(NO|no|N|n|OFF|off|FALSE|False|false)\\b" - constant.bool.false: "\\b(None|null|nil)\\b" # numbers - constant.number: "\\b[0-9](_?[0-9])*(\\.([0-9](_?[0-9])*)?)?(e[0-9](_?[0-9])*)?\\b" # decimal - constant.number: "\\b0b(_?[01])+\\b" # bin - constant.number: "\\b0o(_?[0-7])+\\b" # oct - constant.number: "\\b0x(_?[0-9a-f])+\\b" # hex # operators - symbol.operator: "([~^.:;,+*|=!\\%]|<|>|/|-|&)" # parentheses - symbol.brackets: "([(){}]|\\[|\\])" # string - constant.string: start: "\"" end: "(\"|$)" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "('|$)" skip: "\\\\." rules: - constant.specialChar: "\\\\." # file - preproc: "\\b(FILE|File|file)\\b" # time - identifier: "\\b((([Mm]on|[Tt]ues|[Ww]ed(nes)?|[Tt]hur(s)?|[Ff]ri|[Ss]at(ur)?|[Ss]un)(day)?\\s)?([Jj]an(uary)?|[Ff]eb(ruary)?|[Mm]ar(ch)?|[Aa]pr(il)?|[Mm]ay|[Jj]un(e)?|[Jj]ul(y)?|[Aa]ug(ust)?|[Aa]go|[Ss]ep(tember)?|[Oo]ct(ober)?|[Nn]ov(ember)?|[Dd]ec(ember)?)\\s\\d{1,2},?(\\s\\d{4})?)\\b" # date - identifier: "\\b(\\d{2,4}[-/\\.]?\\d{2,3}[-/\\.]?\\d{2,4})\\b" # date - identifier: "\\b(\\d{2}:\\d{2}(:\\d{2})?([\\.,]?\\d{1,8}[\\.\\+,]?\\d{1,8}?)?([\\.\\+,]?\\d{1,8}[\\.\\+,]?\\d{1,8}?)?([\\.\\+,]?\\d{1,8}?)?(\\s-\\d{0,4})?)\\b" # time - identifier: "^([0-2][0-9][0-2][0-9][-/]?[0-9][0-9][-/]?[0-9][0-9])" # - identifier: "^([0-2][0-9][0-2][0-9][-/]?[0-9][0-9][-/]?[0-9][0-9]\\s[0-9][0-9]:[0-9][0-9](:[0-9][0-9])?(\\.?[0-9][0-9][0-9])?)" - identifier: "^(\\d{4}[-/]?\\d{2}[-/]?\\d{2}\\s\\d{2}:\\d{2}(:\\d{2})?(\\.?\\d{2,8})?)" - identifier: "^([0-2][0-9]|[0-2]-?[0-9][0-9]-?[0-9][0-9])\\-([0-1][0-9])\\-([0-3][0-9]) ([0-2][0-9])\\:([0-5][0-9])\\:([0-5][0-9]),([0-9][0-9][0-9])" # Complete precision: - identifier: "^(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d:[0-5]\\d|Z))" # No milliseconds: - identifier: "^(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z))" # No Seconds: - identifier: "^(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z))" # Putting it all together: - identifier: "^(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d:[0-5]\\d|Z))|(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z))|(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z))" # Complete precision: - identifier: "^(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+)" # No milliseconds - identifier: "^(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d)" # No Seconds - identifier: "^(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d)" # Putting it all together - identifier: "^(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+)|(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d)|(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d)" # link - constant.string.url: start: "https?://" end: "\\s" rules: [] # path # - constant.string.url: "\\b(.+)/([^/]+)\\b" # linux # - constant.string.url: "\\b(^[a-zA-Z]:)\\b" # windowns - diff-modified: "([Cc]ommit:)\\s\\w+\\[\\w+]" zyedidia-micro-6a62575/runtime/syntax/lisp.yaml0000664000175000017510000000076315125206537021115 0ustar nileshnileshfiletype: lisp detect: filename: "(emacs|zile)$|\\.(el|li?sp|scm|ss|rkt)$" rules: - default: "\\([a-z-]+" - symbol: "\\(([\\-+*/<>]|<=|>=)|'" - constant.number: "\\b[0-9]+b>" - special: "\\bnil\\b" - preproc: "\\b[tT]b>" - constant.string: "\\\"(\\\\.|[^\"])*\\\"" - constant.specialChar: "'[A-Za-z][A-Za-z0-9_-]+" - constant.specialChar: "\\\\.?" - comment: "(^|[[:space:]]);.*" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/lilypond.yaml0000664000175000017510000000737315125206537022004 0ustar nileshnileshfiletype: lilypond detect: filename: "\\.ly$|\\.ily$|\\.lly$" rules: - constant.number: "\\d+" - identifier: "\\b(staff|spacing|signature|routine|notes|handler|corrected|beams|arpeggios|Volta_engraver|Voice|Vertical_align_engraver|Vaticana_ligature_engraver|VaticanaVoice|VaticanaStaff|Tweak_engraver|Tuplet_engraver|Trill_spanner_engraver|Timing_translator|Time_signature_performer|Time_signature_engraver|Tie_performer|Tie_engraver|Text_spanner_engraver|Text_engraver|Tempo_performer|Tab_tie_follow_engraver|Tab_staff_symbol_engraver|Tab_note_heads_engraver|TabVoice|TabStaff|System_start_delimiter_engraver|Stem_engraver|Stanza_number_engraver|Stanza_number_align_engraver|Staff_symbol_engraver|Staff_performer|Staff_collecting_engraver|StaffGroup|Staff|Spanner_break_forbid_engraver|Span_bar_stub_engraver|Span_bar_engraver|Span_arpeggio_engraver|Spacing_engraver|Slur_performer|Slur_engraver|Slash_repeat_engraver|Separating_line_group_engraver|Script_row_engraver|Script_engraver|Script_column_engraver|Score|Rhythmic_column_engraver|RhythmicStaff|Rest_engraver|Rest_collision_engraver|Repeat_tie_engraver|Repeat_acknowledge_engraver|Pure_from_neighbor_engraver|Pitched_trill_engraver|Pitch_squash_engraver|Piano_pedal_performer|Piano_pedal_engraver|Piano_pedal_align_engraver|PianoStaff|Phrasing_slur_engraver|PetrucciVoice|PetrucciStaff|Percent_repeat_engraver|Part_combine_engraver|Parenthesis_engraver|Paper_column_engraver|Output_property_engraver|Ottava_spanner_engraver|OneStaff|NullVoice|Note_spacing_engraver|Note_performer|Note_name_engraver|Note_heads_engraver|Note_head_line_engraver|NoteName\\|NoteHead|New_fingering_engraver|Multi_measure_rest_engraver|Midi_control_function_performer|Metronome_mark_engraver|Mensural_ligature_engraver|MensuralVoice|MensuralStaff|Mark_engraver|Lyrics|Lyric_performer|Lyric_engraver|Ligature_bracket_engraver|Ledger_line_engraver|Laissez_vibrer_engraver|Kievan_ligature_engraver|KievanVoice|KievanStaff|Key_performer|Key_engraver|Keep_alive_together_engraver|Instrument_switch_engraver|Instrument_name_engraver|Hyphen_engraver|Grob_pq_engraver|GregorianTranscriptionVoice|GregorianTranscriptionStaff|GrandStaff|Grace_spacing_engraver|Grace_engraver|Grace_beam_engraver|Grace_auto_beam_engraver|Global|Glissando_engraver|Fretboard_engraver|FretBoards|Forbid_line_break_engraver|Footnote_engraver|Font_size_engraver|Fingering_engraver|Fingering_column_engraver|Figured_bass_position_engraver|Figured_bass_engraver|FiguredBass|Extender_engraver|Episema_engraver|Dynamics|Dynamic_performer|Dynamic_engraver|Dynamic_align_engraver|Drum_notes_engraver|Drum_note_performer|DrumVoice|DrumStaff|Double_percent_repeat_engraver|Dots_engraver|Dot_column_engraver|Devnull|Default_bar_line_engraver|Custos_engraver|Cue_clef_engraver|CueVoice|Control_track_performer|Concurrent_hairpin_engraver|Collision_engraver|Cluster_spanner_engraver|Clef_engraver|Chord_tremolo_engraver|Chord_name_engraver|ChordNames|ChoirStaff|Breathing_sign_engraver|Break_align_engraver|Bend_engraver|Beam_performer|Beam_engraver|Beam_collision_engraver|Bar_number_engraver|Bar_engraver|Axis_group_engraver|Auto_beam_engraver|Arpeggio_engraver|Accidental_engraver|Score)\\b" - statement: "[-_^]?\\\\[-A-Za-z_]+" - preproc: "\\b(((gisis|gis|geses|ges|g|fisis|fis|feses|fes|f|eisis|eis|eeses|ees|e|disis|dis|deses|des|d|cisis|cis|ceses|ces|c|bisis|bis|beses|bes|b|aisis|ais|aeses|aes|a)[,']*[?!]?)|s|r|R|q)(128|64|32|16|8|4|2|1|\\\\breve|\\\\longa|\\\\maxima)?([^\\\\\\w]|_|\\b)" - special: "[(){}<>]|\\[|\\]" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "%\\{" end: "%\\}" rules: [] - comment: start: "%" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/lfe.yaml0000664000175000017510000000103315125206537020703 0ustar nileshnileshfiletype: lfe detect: filename: "lfe$|\\.lfe$" rules: - symbol.brackets: "\\(|\\)" - type: "defun|define-syntax|define|defmacro|defmodule|export" - constant: "\\ [A-Za-z][A-Za-z0-9_-]+\\ " - symbol.operator: "\\(([\\-+*/<>]|<=|>=)|'" - constant.number: "\\b[0-9]+\\b" - constant.string: "\\\"(\\\\.|[^\"])*\\\"" - special: "['|`][A-Za-z][A-Za-z0-9_\\-]+" - constant.specialChar: "\\\\.?" - comment: "(^|[[:space:]]);.*" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/ledger.yaml0000664000175000017510000000074615125206537021411 0ustar nileshnileshfiletype: ledger detect: filename: "(^|\\.|/)(ledger|ldgr|beancount|bnct)$" rules: - special: "^([0-9]{4}(/|-)[0-9]{2}(/|-)[0-9]{2}|[=~]) .*" - constant: "^[0-9]{4}(/|-)[0-9]{2}(/|-)[0-9]{2}" - statement: "^~ .*" - identifier.var: "^= .*" - identifier: "^[[:space:]]+(![[:space:]]+)?\\(?[A-Za-z ]+(:[A-Za-z ]+)*\\)?" - identifier: "^[[:space:]]+(![[:space:]]+)?\\(?[A-Za-z_\\-]+(:[A-Za-z_\\-]+)*\\)?" - symbol: "[*!]" - comment: "^[[:space:]]*;.*" zyedidia-micro-6a62575/runtime/syntax/kvlang.yaml0000664000175000017510000000376415125206537021434 0ustar nileshnileshfiletype: "kvlang" detect: filename: "\\.kv$" rules: # layouts - special: "\\b[a-z].+" - identifier: "\\b(self|app|root)\\b" - type: "\\b[A-Z].+" - type: "\\b(AnchorLayout|BoxLayout|FloatLayout|RelativeLayout|GridLayout|PageLayout|StackLayout)\\b" - type: "\\b(canvas)\\b" # functions - identifier.function: "[a-zA-Z_0-9]+\\(" # built-in functions - type: "\\b(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes)\\b" - type: "\\b(callable|chr|classmethod|compile|copyright|credits|oct)\\b" - type: "\\b(delattr|dict|dir|display|divmod|enumerate|eval|filter)\\b" - type: "\\b(float|format|frozenset|get_ipython|getattr|globals|type)\\b" - type: "\\b(hash|help|hex|id|input|int|isinstance|issubclass|iter|len)\\b" - type: "\\b(license|list|locals|map|max|memoryview|min|next|object)\\b" - type: "\\b(open|ord|pow|print|property|range|repr|reversed|round|set)\\b" - type: "\\b(setattr|slice|sorted|staticmethod|hasattr|super|tuple|str)\\b" - type: "\\b(vars|zip|exec|sum|complex)\\b" # keywords - statement.built_in: "\\b(and|as|assert|async|await|break|class|continue|def)\\b" - statement.built_in: "\\b(del|elif|else|except|finally|for|from|global|if)\\b" - statement.built_in: "\\b(import|in|is|lambda|nonlocal|not|or|pass|raise)\\b" - statement.built_in: "\\b(return|try|while|with|yield|match|case)\\b" # operators - symbol.operator: "([~^.:;,+*|=!\\%]|<|>|/|-|&)" # parentheses - symbol.brackets: "([(){}]|\\[|\\])" # numbers - constant.number: "\\b[0-9](_?[0-9])*(\\.([0-9](_?[0-9])*)?)?(e[0-9](_?[0-9])*)?\\b" # decimal - constant.number: "\\b0b(_?[01])+\\b" # bin - constant.number: "\\b0o(_?[0-7])+\\b" # oct - constant.number: "\\b0x(_?[0-9a-f])+\\b" # hex - constant.bool.none: "\\b(None)\\b" - constant.bool.true: "\\b(True)\\b" - constant.bool.false: "\\b(False)\\b" # strings - constant.string: start: "\"" end: "(\"|$)" skip: "\\\\." rules: [] - constant.string: start: "'" end: "('|$)" skip: "\\\\." rules: [] - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/kotlin.yaml0000664000175000017510000000342315125206537021442 0ustar nileshnileshfiletype: kotlin detect: filename: "\\.kts?$" rules: # Operators - symbol.operator: ([.:;,+*|=!?\\%]|<|>|/|-|&) # Statements Keywords - statement: \b(as|by|class|constructor|companion|const|fun|import|in|infix|interface|inline|is|out|operator|package|return|suspend|super|this|when|val|var)\b - statement.properties: \b(get|set)\b - statement.control: \b(break|continue|else|do|if|try|catch|finally|for|while)\b - statement.class: \b(abstract|annotation|data|enum|final|open|sealed)\b - statement.member: \b(override|lateinit|init)\b - statement.access: \b(internal|private|protected|public)\b - statement.parameter: \b(crossinline|noinline|reified|vararg)\b # Expression and types - type: \b(dynamic|object|throw|typealias)\b # Meta - statement.meta: \@(\bfile|delegate|field|get|property|receiver|set|setparam|param|)\b # Constant - constant: \b(true|false|null) - constant.number: ([0-9]+) # Storage Types - type.storage: \b(Byte|UByte|Char|Double|Float|Int|UInt|Long|ULong|Short|UShort|Boolean|Unit|Nothing)\b # Collections - type.collections: \b(Array)\b # String - constant.string: start: \" end: \" skip: \\. rules: - constant.specialChar: (\\0|\\\\|\\t|\\n|\\r|\\"|\\') - constant.unicode: \\u\{[[:xdigit:]]+} # Shebang Line - comment.shebang: ^(#!).* # Line Comment - comment.line: "//.*" # Block Comment - comment.block: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" # Doc Block Comment - comment.block: start: "/\\*\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" # Todo - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/kickstart.yaml0000664000175000017510000000117115125206537022137 0ustar nileshnileshfiletype: kickstart detect: filename: "\\.ks$|\\.kickstart$" rules: - special: "%[a-z]+" - statement: "^[[:space:]]*(install|cdrom|text|graphical|volgroup|logvol|reboot|timezone|lang|keyboard|authconfig|firstboot|rootpw|user|firewall|selinux|repo|part|partition|clearpart|bootloader)" - constant: "--(name|mirrorlist|baseurl|utc)(=|\\>)" - statement: "\\$(releasever|basearch)\\>" - brightblack: "^@[A-Za-z][A-Za-z-]*" - brightred: "^-@[a-zA-Z0-9*-]+" - red: "^-[a-zA-Z0-9*-]+" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/keymap.yaml0000664000175000017510000000114415125206537021426 0ustar nileshnileshfiletype: keymap detect: filename: "\\.(k|key)?map$|Xmodmap$" rules: - statement: "\\b(add|clear|compose|keycode|keymaps|keysym|remove|string)\\b" - statement: "\\b(control|alt|shift)\\b" - constant.number: "\\b[0-9]+\\b" - special: "=" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "^!" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/justfile.yaml0000664000175000017510000000323415125206537021767 0ustar nileshnilesh# For more information, see https://github.com/casey/just filetype: 'justfile' detect: filename: "(^\\.?[Jj]ustfile|\\.just)$" header: "^#!.*/(env +)?[bg]?just --justfile" rules: - preproc: "\\<(ifeq|ifdef|ifneq|ifndef|else|endif)\\>" - statement: "^(export|include|override)\\>" - symbol.operator: "^[^:= ]+:" - symbol.operator: "([=,%]|\\+=|\\?=|:=|&&|\\|\\|)" - statement: "\\$\\((abspath|addprefix|addsuffix|and|basename|call|dir)[[:space:]]" - statement: "\\$\\((error|eval|filter|filter-out|findstring|firstword)[[:space:]]" - statement: "\\$\\((flavor|foreach|if|info|join|lastword|notdir|or)[[:space:]]" - statement: "\\$\\((origin|patsubst|realpath|shell|sort|strip|suffix)[[:space:]]" - statement: "\\$\\((value|warning|wildcard|word|wordlist|words)[[:space:]]" # default functions - probably shouldn't be overwritten by assignment - statement: "\\b(arch|os|os_family|env_var|invocation_directory|justfile|justfile_directory|just_executable|lowercase|quote|replace|trim|trim_end|trim_end|trim_end_match|trim_end_matches|trim_start|trim_start_match|trim_start_matches|uppercase)\\b" - identifier: "^.+:" - identifier: "[()$]" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - identifier: "\\$+(\\{[^} ]+\\}|\\([^) ]+\\))" - identifier: "\\$[@^<*?%|+]|\\$\\([@^<*?%+-][DF]\\)" - identifier: "\\$\\$|\\\\.?" - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/julia.yaml0000664000175000017510000000334715125206537021253 0ustar nileshnileshfiletype: julia detect: filename: "\\.jl$" header: "^#!.*/(env +)?julia( |$)" rules: # built-in objects - constant.bool: "\\b(true|false)\\b" - constant: "\\b(nothing|missing)\\b" # built-in attributes - constant: "__[A-Za-z0-9_]+__" # definitions - identifier: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]" # keywords - statement: "\\b(baremodule|begin|break|catch|const|continue|do|else|elseif|end|export|finally|for|function|global|if|import|let|local|macro|module|public|quote|return|struct|try|using|while)\\b" - statement: "\\b(abstract\\s+type|primitive\\s+type|mutable\\s+struct)\\b" # decorators - identifier.macro: "@[A-Za-z0-9_]+" # operators - symbol.operator: "[:+*|=!%~<>/\\-?&\\\\÷∈∉∘]|\\b(in|isa|where)\\b" # for some reason having ^ in the same regex with the other operators broke things - symbol.operator: "\\^" # parentheses - symbol.brackets: "([(){}]|\\[|\\])" # numbers - constant.number: "\\b([0-9]+(_[0-9]+)*|0x[0-9a-fA-F]+(_[0-9a-fA-F]+)*|0b[01]+(_[01]+)*|0o[0-7]+(_[0-7]+)*|Inf(16|32|64)?|NaN(16|32|64)?)\\b" - constant.string: start: "\"\"\"" end: "\"\"\"" rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{1,4}|U[0-9A-Fa-f]{1,8})" # Lifted from Rust's syntax highlighting - constant.string: "'(\\\\.|.)'" - constant.string: start: "'\"" end: "'" rules: [] - comment: start: "#=" end: "=#" rules: [] - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/jsonnet.yaml0000664000175000017510000000627515125206537021632 0ustar nileshnileshfiletype: jsonnet detect: filename: "\\.jsonnet$" # Spec: https://jsonnet.org/ref/spec.html rules: # built-in objects # FIXME: $ won't match - constant: "\\b(self|\\$|super)\\b" # boolean constants - constant.bool: "\\b(null|true|false)\\b" # the standard library - identifier: "\\bstd\\.(extVar|thisFile|type|length|objectHas|objectFields|objectHasAll|objectFieldsAll|prune|mapWithKey|abs|sign|max|min|pow|exp|log|exponent|mantissa|floor|ceil|sqrt|sin|cos|tan|asin|acos|atan|mod|assertEqual|toString|codepoint|char|substr|findSubstr|startsWith|endsWith|split|splitLimit|strReplace|asciiUpper|asciiLower|stringChars|format|escapeStringDollars|escapeStringPython|parseInt|parseOctal|parseHex|parseJson|encodeUTF8|decodeUTF8|manifestIni|manifestPython|manifestPythonVars|manifestJsonEx|manifestYamlDoc|manifestYamlStream|manifestXmlJsonml|makeArray|count|find|map|mapWithIndex|filterMap|filter|foldl|foldr|range|join|lines|flattenArrays|sort|uniq|set|setInter|setUnion|setDiff|setMember|base64|base64DecodeBytes|base64Decode|md5|mergePatch|trace)\\b" # unquoted object keys - type: "[_a-zA-Z][_a-zA-Z0-9]*\\s*:" # object key separator - statement: ":" # keywords - statement: "\\b(assert|else|error|for|function|if|import|importstr|in|local|tailstrict|then)\\b" # operators - symbol.operator: "([.;,+*|=!\\%]|<|>|/|-|&)" # parentheses - symbol.brackets: "([(){}]|\\[|\\])" # numbers - constant.number: "\\b(0|([1-9][0-9]*))(\\.[0-9]+)?([eE][\\+-]?[0-9]+)?\\b" # double-quoted string - constant.string: start: "\"" end: "\"" skip: "\\\\\"" rules: - constant.specialChar: "\\\\u[0-9a-fA-F]{4}|\\\\[bfnrt'\"/\\\\]" # single-quoted string - constant.string: start: "'" end: "'" skip: "\\\\'" rules: - constant.specialChar: "\\\\u[0-9a-fA-F]{4}|\\\\[bfnrt'\"/\\\\]" # double-quoted verbatim string - constant.string: start: "@\"" end: "\"" skip: "\\\\\"" rules: - constant.specialChar: "\\\\\"" # single-quoted verbatim string - constant.string: start: "@'" end: "'" skip: "\\\\'" rules: - constant.specialChar: "\\\\'" # block string - constant.string: # FIXME: # This isn't quite right. # The spec says this: # beginning with |||, followed by optional whitespace and a new-line. # The next non-blank line must be prefixed with some non-zero length # whitespace W. The block ends at the first subsequent line that does # not begin with W, and it is an error if this line does not contain # some optional whitespace followed by |||. # We need to match ^(\s+) on the first non-blank line after ||| # Then we need to skip ^\1.*$ start: "\\|\\|\\| *$" end: "^ *\\|\\|\\|" rules: [] # multi-line comment - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" # single-line comment - comment: start: "#|(//)" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/json.yaml0000664000175000017510000000203415125206537021110 0ustar nileshnileshfiletype: json detect: filename: "\\.json$" header: "^\\{$" rules: - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b" - constant.number: "\\b[-+]?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?" - constant.number: "\\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?" - constant: "\\b(null)\\b" - constant: "\\b(true|false)\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - statement: "\\\"(\\\\\"|[^\"])*\\\"[[:space:]]*:\" \"'(\\'|[^'])*'[[:space:]]*:" - constant: "\\\\u[0-9a-fA-F]{4}|\\\\[bfnrt'\"/\\\\]" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/jinja2.yaml0000664000175000017510000000210715125206537021315 0ustar nileshnileshfiletype: jinja2 rules: - include: "html" - special: "({{|}}|{%-?|-?%})" - default: start: "({%-?|{{)" end: "(-?%}|}})" limit-group: special rules: - include: "python" - statement: "\\b(ignore missing|with(out)? context|block|call|endblock|endcall|endfilter|endfor|endmacro|endraw|endset|extends|filter|for|include|macro|raw|recursive|scoped|set)\\b" - identifier.builtinfunc: "\\b(attr|batch|capitalize|center|count|d|default|dictsort|e|escape|filesizeformat|first|forceescape|groupby|indent|join|last|length|lower|pprint|random|reject|rejectattr|replace|reverse|safe|select|selectattr|striptags|title|tojson|trim|truncate|unique|upper|urlencode|urlize|wordcount|wordwrap|xmlattr)\\b" - identifier.builtintest: "\\b(callable|defined|divisibleby|eq|equalto|escaped|even|ge|gt|iterable|le|lower|lt|mapping|ne|none|number|odd|sameas|sequence|string|undefined|upper)\\b" - identifier.defaultglobal: "\\b(lipsum|cycler|joiner|namespace)\\b" - comment: start: "{#" end: "#}" rules: [] zyedidia-micro-6a62575/runtime/syntax/javascript.yaml0000664000175000017510000000544415125206537022315 0ustar nileshnileshfiletype: javascript detect: filename: "(\\.(m|c)?js$|\\.es[5678]?$)" header: "^#!.*/(env +)?node( |$)" rules: - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b" - constant.number: "\\b[-+]?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?" - constant.number: "\\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?" #- identifier: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]" # ^ this is not correct usage of the identifier color - symbol.brackets: "[(){}]|\\[|\\]" - symbol.operator: "([-+/*=<>!~%?:&|]|[.]{3})" - statement: "\\b(async|await|break|case|catch|const|continue|debugger|default)\\b" - statement: "\\b(delete|do|else|export|finally|for|function\\*?|class|extends)\\b" - statement: "\\b(get|if|import|from|in|of|instanceof|let|new|reject|resolve|return)\\b" - statement: "\\b(set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\\b" # reserved but unassigned - error: "\\b(enum|implements|interface|package|private|protected|public)\\b" - constant: "\\b(globalThis|Infinity|null|undefined|NaN)\\b" - constant: "\\b(null|undefined|NaN)\\b" - constant: "\\b(true|false)\\b" - type: "\\b(Array|Boolean|Date|Enumerator|Error|Function|Generator|Map|Math)\\b" - type: "\\b(Number|Object|Promise|Proxy|Reflect|RegExp|Set|String|Symbol|WeakMap|WeakSet)\\b" - type: "\\b(BigInt64Array|BigUint64Array|Float32Array|Float64Array|Int16Array)\\b" # - constant: "/[^*]([^/]|(\\\\/))*[^\\\\]/[gim]*" - constant: "\\\\[0-7][0-7]?[0-7]?|\\\\x[0-9a-fA-F]+|\\\\[bfnrt'\"\\?\\\\]" - comment: "^#!.*/(env +)?node( |$)" - identifier: "\\b(alert|decodeURI|decodeURIComponent|document|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|uneval|window)\\b" - identifier: "\\b(Intl|WebAssembly)\\b" - identifier: "\\b(Arguments)\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "`" end: "`" rules: - constant.specialChar: "\\\\." - identifier: "\\x24\\{.*?\\}" - constant.bool: "\\b(true|false)\\b" - constant.bool.false: "\\b(false)\\b" - constant.bool.true: "\\b(true)\\b" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME)" - comment: start: "/\\*" end: "\\*/" skip: "\\\\." rules: - constant.specialChar: "\\\\." # function documentation - identifier: "\\s\\*\\s.*" - todo: "(TODO|XXX|FIXME)" zyedidia-micro-6a62575/runtime/syntax/java.yaml0000664000175000017510000000173515125206537021067 0ustar nileshnileshfiletype: java detect: filename: "\\.java$" rules: - type: "\\b(boolean|byte|char|double|float|int|long|new|var|short|this|transient|void)\\b" - statement: "\\b(break|case|catch|continue|default|do|else|finally|for|if|return|switch|throw|try|while)\\b" - type: "\\b(abstract|class|extends|final|implements|import|instanceof|interface|native|package|private|protected|public|static|strictfp|super|synchronized|throws|volatile)\\b" - constant: "\\b(true|false|null)\\b" - constant.number: "\\b[0-9]+\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - preproc: "..+" - constant.specialChar: "\\\\." - comment: start: "//" end: "$" rules: [] - comment: start: "/\\*" end: "\\*/" rules: [] zyedidia-micro-6a62575/runtime/syntax/inputrc.yaml0000664000175000017510000000061715125206537021630 0ustar nileshnileshfiletype: inputrc detect: filename: "inputrc$" rules: - constant.bool.false: "\\b(off|none)\\b" - constant.bool.true: "\\bon\\b" - preproc: "\\bset|\\$include\\b" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - constant.specialChar: "\\\\.?" - comment: "(^|[[:space:]])#([^{].*)?$" - indent-char.whitespace: "[[:space:]]+$" - indent-char: " + +| + +" zyedidia-micro-6a62575/runtime/syntax/ini.yaml0000664000175000017510000000115515125206537020721 0ustar nileshnileshfiletype: ini detect: filename: "\\.(ini|desktop|lfl|override|tscn|tres)$|(mimeapps\\.list|pinforc|setup\\.cfg|project\\.godot)$|weechat/.+\\.conf$" rules: - constant.bool.true: "\\btrue\\b" - constant.bool.false: "\\bfalse\\b" - identifier: "^[[:space:]]*[^=]*=" - special: "^[[:space:]]*\\[.*\\]$" - statement: "[=;]" - constant.string: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: ";" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/html5.yaml0000664000175000017510000000243515125206537021175 0ustar nileshnileshfiletype: html5 detect: filename: "\\.htm[l]?5$" header: "" rules: - error: "<[^!].*?>" - symbol.tag: "(?i)<[/]?(a|a(bbr|ddress|rea|rticle|side|udio)|b|b(ase|d(i|o)|lockquote|r|utton)|ca(nvas|ption)|center|cite|co(de|l|lgroup)|d(ata|atalist|d|el|etails|fn|ialog|l|t)|em|embed|fieldset|fig(caption|ure)|form|iframe|h[1-6]|hr|i|img|in(put|s)|kbd|keygen|label|legend|li|link|ma(in|p|rk)|menu|menuitem|met(a|er)|nav|noscript|o(bject|l|pt(group|ion)|utput)|p|param|picture|pre|progress|q|r(p|t|uby)|s|samp|se(ction|lect)|small|source|span|strong|su(b|p|mmary)|textarea|time|track|u|ul|var|video|wbr)( .*)*?>" - symbol.tag.extended: "(?i)<[/]?(body|div|html|head(er)?|footer|title|table|t(body|d|h(ead)?|r|foot))( .*)*?>" - preproc: "(?i)<[/]?(script|style)( .*)*?>" - special: "&[^;[[:space:]]]*;" - symbol: "[:=]" - identifier: "(alt|bgcolor|height|href|id|label|longdesc|name|on(click|focus|load|mouseover)|size|span|src|style|target|type|value|width)=" - constant.string: "\"[^\"]*\"" - constant.number: "(?i)#[0-9a-fA-F]{6,6}" - default: start: ">" end: "<" rules: [] - symbol.tag: "<|>" - constant.string.url: "(ftp(s)?|http(s)?|git|chrome)://[^ ]+" - comment: "" - preproc: "" zyedidia-micro-6a62575/runtime/syntax/html4.yaml0000664000175000017510000000262315125206537021173 0ustar nileshnileshfiletype: html4 detect: filename: "\\.htm[l]?4$" header: "" rules: - error: "<[^!].*?>" - symbol.tag: "(?i)<[/]?(a(bbr|cronym|ddress|pplet|rea|rticle|side|udio)?|b(ase(font)?|d(i|o)|ig|lockquote|r)?|ca(nvas|ption)|center|cite|co(de|l|lgroup)|d(ata(list)?|d|el|etails|fn|ialog|ir|l|t)|em(bed)?|fieldset|fig(caption|ure)|font|form|(i)?frame|frameset|h[1-6]|hr|i|img|in(put|s)|kbd|keygen|label|legend|li(nk)?|ma(in|p|rk)|menu(item)?|met(a|er)|nav|no(frames|script)|o(l|pt(group|ion)|utput)|p(aram|icture|re|rogress)?|q|r(p|t|uby)|s(trike)?|samp|se(ction|lect)|small|source|span|strong|su(b|p|mmary)|textarea|time|track|u(l)?|var|video|wbr)( .*|>)*?>" - symbol.tag.extended: "(?i)<[/]?(body|div|html|head(er)?|footer|title|table|t(body|d|h(ead)?|r|foot))( .*)*?>" - preproc: "(?i)<[/]?(script|style)( .*)*?>" - special: "&[^;[[:space:]]]*;" - symbol: "[:=]" - identifier: "(alt|bgcolor|height|href|id|label|longdesc|name|on(click|focus|load|mouseover)|size|span|src|style|target|type|value|width)=" - constant.string: "\"[^\"]*\"" - constant.number: "(?i)#[0-9a-fA-F]{6,6}" - default: start: ">" end: "<" rules: [] - symbol.tag: "<|>" - constant.string.url: "(ftp(s)?|http(s)?|git|chrome)://[^ ]+" - comment: "" - preproc: "" zyedidia-micro-6a62575/runtime/syntax/html.yaml0000664000175000017510000000670015125206537021107 0ustar nileshnileshfiletype: html detect: filename: "\\.htm[l]?$" rules: # Doctype is case-insensitive - preproc: "" # Opening tag - symbol.tag: start: "<(a|abbr|acronym|address|applet|area|article|aside|audio|b|base|bdi|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|dialog|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h[1-6]|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|main|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|section|select|small|source|span|strike|strong|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|track|tt|u|ul|var|video|wbr)\\b" end: ">" rules: - identifier: "\\b(placeholder|style|alt|bgcolor|height|href|id|(aria|data)\\-.+|label|longdesc|name|on(click|focus|load|mouseover)|size|span|src|target|type|value|width|class|charset|content|rel|integrity|crossorigin|for|onsubmit|lang|role)\\b" - special: "\\b(required)\\b" # Match double-quote strings - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string.url: "((ftp(s)?|http(s)?|git|chrome)://[^\\s]+)" # Match single-quote strings - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string.url: "((ftp(s)?|http(s)?|git|chrome)://[^\\s]+)" # Highlight the equals and any colon between words - symbol: "\\b(=|:\\b)" # Closing tag - symbol.tag: start: "" rules: # Anything in the closing tag is an error - error: "." # Reserved entities like a   and Ī - special: "(([a-zA-Z]&#[0-9]+|&[a-zA-Z]+|&#[a-zA-Z0-9]+);)" # TODO: Add `limit-rules` to both the `default` rules below once it's implemented into Micro - default: start: "" end: "" limit-group: symbol.tag rules: - include: "javascript" - default: start: "" end: "" limit-group: symbol.tag rules: - include: "css" # This weird empty comment thing is technically valid - comment: "" - comment.block: start: "" rules: - todo: "(FIXME|NOTE|TODO):?" # While technically not a "true" error, these are recommended to not be used inside a comment - error: "(\\-\\-|>)" zyedidia-micro-6a62575/runtime/syntax/hc.yaml0000664000175000017510000000354115125206537020535 0ustar nileshnileshfiletype: hc detect: filename: "(\\.(hc|HC)$|\\.(hh|HH)$|\\.ii?$|\\.(def)$)" rules: - identifier: "\\b[A-Z_][0-9A-Z_]+\\b" - type: "\\b(F64|I8|U8|I16|U16|I32|U32|I64|U64|sizeof|enum|U0|static|extern|struct|union|class|intern|public|argc|argv|asm)\\b" - statement: "\\b(for|if|while|do|else|case|default|switch)\\b" - statement: "\\b(try|catch|throw|goto|continue|break|return)\\b" - preproc: "^[[:space:]]*#[[:space:]]*(define|pragma|include|(un|ifn?)def|endif|el(if|se)|if|help_index|ifjit|ifaot|exe)" # Operator Color - symbol.operator: "([.:;,+*|=!\\%]|<|>|/|-|&)" - symbol.brackets: "[(){}]|\\[|\\]" # Integer Constants - constant.number: "(\\b([1-9][0-9]*|0[0-7]*|0[Xx][0-9A-Fa-f]+|0[Bb][01]+)([Uu]?[Ll][Ll]?|[Ll][Ll]?[Uu]?)?\\b)" # Decimal Floating Constants - constant.number: "(\\b(([0-9]*[.][0-9]+|[0-9]+[.][0-9]*)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)[FfLl]?\\b)" # Hexadecimal Floating Constants - constant.number: "(\\b0[Xx]([0-9A-Za-z]*[.][0-9A-Za-z]+|[0-9A-Za-z]+[.][0-9A-Za-z]*)[Pp][+-]?[0-9]+[FfLl]?\\b)" - constant.number: "NULL" - constant.number: "TRUE" - constant.number: "FALSE" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - error: "..+" - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/haskell.yaml0000664000175000017510000000332015125206537021561 0ustar nileshnileshfiletype: haskell detect: filename: "\\.hs$" rules: - symbol.operator: "[!#$%&:*+/<=>?@.\\\\^\\|~\\p{Sm}\\-]+" # Identifiers (with or without a module name) - type: "\\b([A-Z][A-Za-z0-9_]*\\.)*[A-Z]+[A-Za-z0-9_']*\\b" - default: "\\b([A-Z][A-Za-z0-9_]*\\.)*[a-z][A-Za-z0-9_']*\\b" - statement: ";" - symbol.bracket: "[\\(\\)\\[\\]\\{\\}]" - special: "`[A-Za-z0-9']+`" # Keywords - statement: "\\b(case|of|class|data|default|deriving|do|forall|foreign|hiding|if|then|else|import|infix|infixl|infixr|instance|let|in|mdo|module|newtype|qualified|type|where)\\b" # Data constructors - constant.bool: "\\b(True|False)\\b" - constant: "\\b(Nothing|Just|Left|Right|LT|EQ|GT)\\b" - constant: "\\(\\)" # Unit - constant.number: "\\b(0[xX][0-9A-Fa-f]+|0[oO][0-7]+|0[bB][01]+|[-]?[0-9]+([.][0-9]+)?([eE][+-]?[0-9]+)?)\\b" # Data classes - identifier.class: "\\b(Additive|Applicative|Bounded|Data|Enum|Eq|Floating|Foldable|Fractional|Functor|Integral|Monad|MonadPlus|Monoid|Num|Ord|Read|Real|RealFloat|RealFrac|Semigroup|Show|Traversable|Typeable|Zip)[ ]" # Strings - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - special: "\\\\&" - constant.specialChar: "\\\\([abfnrtv\"'\\\\]|[0-9]+|x[0-9a-fA-F]+|o[0-7]+|NUL|SOH|STX|ETX|EOT|ENQ|ACK|BEL|BS|HT|LF|VT|FF|CR|SO|SI|DLE|DC[1-4]|NAK|SYN|ETB|CAN|EM|SUB|ESC|FS|GS|RS|US|SP|DEL)" # Comments - comment: start: "--" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "\\{-" end: "-\\}" rules: - todo: "(TODO|XXX|FIXME):?" - identifier.macro: "undefined" zyedidia-micro-6a62575/runtime/syntax/hare.yaml0000664000175000017510000000333615125206537021064 0ustar nileshnileshfiletype: hare detect: filename: "\\.ha$" rules: - identifier: "\\b[A-Z_][0-9A-Z_]+\\b" - type: "\\b(bool|char|str|rune|void)\\b" - type: "\\b(f32|f64|uint|int|u8|u16|u32|u64|i8|i16|i32|i64|uintptr)\\b" - statement: "\\b(case|else|for|if|switch)\\b" - statement: "\\b(continue|break|return)\\b" - special: "\\b(as|const|def|defer|enum|export|fn|is|let|match|static|struct|type|union|yield|_)\\b" - preproc: "\\b(abort|alloc|append|assert|delete|free|insert|len|nullable|offset|size)\\b" - preproc: "^use .+;" - preproc: "\\@([a-zA-Z_][0-9a-zA-Z_]+)\\b" - constant: "\\b(false|null|true)\\b" - constant.number: "\\b(0x[0-9A-Fa-f]+(i(8|16|32|64)?|u(8|16|32|64)?|z)?)\\b" - constant.number: "\\b(0o[0-7]+(i(8|16|32|64)?|u(8|16|32|64)?|z)?)\\b" - constant.number: "\\b(0b[01]+(i(8|16|32|64)?|u(8|16|32|64)?|z)?)\\b" - constant.specialChar: "\\\".*\\\"" - constant.specialChar: "`.*`" - constant.specialChar: "'([^'\\\\]|\\\\(0|a|b|f|n|r|t|v|\\\\|'|\\\"|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8}))'" - symbol.operator: "([.:;,+*|=!\\%]|<|>|/|-|&)" - symbol.brackets: "[(){}]|\\[|\\]" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - error: "..+" - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/haml.yaml0000664000175000017510000000114315125206537021060 0ustar nileshnileshfiletype: haml detect: filename: "\\.haml$" rules: - symbol: "-|=" - default: "->|=>" - constant: "([ ]|^)%[0-9A-Za-z_]+>" - special: ":[0-9A-Za-z_]+>" - type: "\\.[A-Za-z_]+>" - constant.string: "\"([^\"]|(\\\\\"))*\"|%[QW]?\\{[^}]*\\}|%[QW]?\\([^)]*\\)|%[QW]?<[^>]*>|%[QW]?\\$[^$]*\\$|%[QW]?\\^[^^]*\\^|%[QW]?![^!]*!" - constant.string: "'([^']|(\\\\'))*'|%[qw]\\{[^}]*\\}|%[qw]\\([^)]*\\)|%[qw]<[^>]*>|%[qw]\\[[^]]*\\]|%[qw]\\$[^$]*\\$|%[qw]\\^[^^]*\\^|%[qw]![^!]*!" - identifier: "#\\{[^}]*\\}" - identifier.var: "(@|@@)[0-9A-Z_a-z]+" - comment: "#[^{].*$|#$" zyedidia-micro-6a62575/runtime/syntax/groovy.yaml0000664000175000017510000000734715125206537021500 0ustar nileshnileshfiletype: groovy detect: filename: "(\\.(groovy|gy|gvy|gsh|gradle)$|^[Jj]enkinsfile$)" header: "^#!.*/(env +)?groovy *$" rules: # And the style guide for constants is CONSTANT_CASE - identifier: "\\b[A-Z_$]+\\b" # The style guide for JVM languages is PascalCase for classes and interfaces - identifier.class: "\\b[A-Z][a-zA-Z0-9$]+\\b" # Primitive types - type: "\\b(byte|short|int|long|float|double|char|boolean|void)\\b" # Type-related keywords - type.keyword: "\\b(private|public|protected|static|final|var|def)\\b" # Keywords - statement: "\\b(for|while|do|if|else|switch|case|default|try|catch|finally)\\b" - statement: "\\b(break|continue|return|throw|assert)\\b" - statement: "\\b(package|import|class|interface|trait|enum|extends|implements|throws)\\b" - statement: "\\b(this|super)\\b" # Unsused, but reserved keywords - statement: "\\b(goto|const)\\b" # Operators and punctuation - symbol.operator: "[-+*/%=<>^~&|!?:;,.@]|\\b(in|is|as|instanceof|new)\\b" - symbol.brackets: "[(){}]|\\[|\\]" # Decimal integer literal - constant.number: "(?i)\\b[1-9]([_0-9]*[0-9])?[GLIDF]?\\b" # Binary integer literal - constant.number: "(?i)\\b0b[01]([01_]*[01])?[GLIDF]?\\b" # Octal integer literal - constant.number: "(?i)\\b0[0-7]([0-7_]*[0-7])?[GLIDF]?\\b" # Hexadecimal integer literal - constant.number: "(?i)\\b0x[0-9a-fA-F]([0-9a-f_]*[0-9a-fA-F])?[GLIDF]?\\b" # Floating-point literal - constant.number: "(?i)\\b[0-9]([0-9_]*[0-9])?([.][0-9]([0-9_]*[0-9])?)?(e[+-]?[0-9]([0-9_]*[0-9])?)?[DF]?\\b" - constant.bool: "\\b(true|false|null)\\b" # Annotations - identifier: "@[A-Za-z_$][A-Za-z0-9_$]*\\b" # Triple-double-quoted strings - constant.string: start: "\"\"\"" end: "\"\"\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'bfnrst\\x24\\\\]|u[a-fA-F0-9]{4})" - identifier.var: "\\x24[\\w\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\uFFFE]+([.][a-zA-Z0-9_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\uFFFE]+)*" - identifier: start: "[$][{]" end: "[}]" rules: [] # Triple-single-quoted strings - constant.string: start: "'''" end: "'''" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'bfnrst\\x24\\\\]|u[a-fA-F0-9]{4})" # Nesting ${} are never going to be matched correctly with just regex either, so highlighting will break if one is to nest interpolation # Double-quoted strings - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'bfnrst\\x24\\\\]|u[a-fA-F0-9]{4})" - identifier.var: "\\x24[\\w\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\uFFFE]+([.][a-zA-Z0-9_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\uFFFE]+)*" - identifier: "\\x24[{].*[}]" # Single-quoted strings - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'bfnrst\\x24\\\\]|u[a-fA-F0-9]{4})" # Slashy strings are left out, because they match in unwanted places pretty much all the time # Dollar-slashy strings - constant.string: start: "[$]/" end: "/[$]" rules: [] # Single-line comments - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" # Multiline comments - comment: start: "/[*]" end: "[*]/" rules: - todo: "(TODO|XXX|FIXME):?" # Groovydoc comments - comment: start: "/[*][*]@?" end: "[*]/" rules: [] zyedidia-micro-6a62575/runtime/syntax/groff.yaml0000664000175000017510000000140015125206537021236 0ustar nileshnileshfiletype: groff detect: filename: "\\.m[ems]$|\\.rof|\\.tmac$|^tmac." rules: - statement: "^\\.(ds|nr) [^[[:space:]]]*" - constant.specialChar: "\\\\." - constant.specialChar: "\\\\f.|\\\\f\\(..|\\\\s(\\+|\\-)?[0-9]" - constant: "(\\\\|\\\\\\\\)n(.|\\(..)" - constant: start: "(\\\\|\\\\\\\\)n\\[" end: "]" rules: [] - type: "^\\.[[:space:]]*[^[[:space:]]]*" - comment: "^\\.\\\\\".*$" - constant.string: "(\\\\|\\\\\\\\)\\*(.|\\(..)" - constant.string: start: "(\\\\|\\\\\\\\)\\*\\[" end: "]" rules: [] - constant.specialChar: "\\\\\\(.." - constant.specialChar: start: "\\\\\\[" end: "]" rules: [] - identifier.macro: "\\\\\\\\\\$[1-9]" zyedidia-micro-6a62575/runtime/syntax/graphql.yaml0000664000175000017510000000223115125206537021574 0ustar nileshnileshfiletype: graphql detect: filename: "\\.(gql|graphql)$" rules: - type: "\\b(?:(query|mutation|subscription|type|input|scalar|fragment|schema|union|on|extends?))\\b" # scalar types - statement: "\\b(ID|Int|Float|Boolean|String|Datetime|Null)\\b" # introspection types - statement: "(__\\w+)" # parameters - statement: "((\\w+)(?:\\:([\\s]*)?)(?:\\$))" # directive locations - statement: "\\b(QUERY|MUTATION|SUBSCRIPTION|FIELD|FRAGMENT_DEFINITION|FRAGMENT_SPREAD|INLINE_FRAGMENT|SCHEMA|SCALAR|OBJECT|FIELD_DEFINITION|ARGUMENT_DEFINITION|INTERFACE|UNION|ENUM|ENUM_VALUE|INPUT_OBJECT|INPUT_FIELD_DEFINITION)\\b" # directives - constant: "(@\\w+)" # root types - constant: "\\b(Query|Mutation|Subscription|Schema|Root)\\b" # variables - special: "(\\$\\w+)" # required symbol - special: "(!)" - symbol: "(:|=|\\||\\(|\\)|\\{|\\}|\\[|\\])" - constant.bool: "\\b(true|false)\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/gomod.yaml0000664000175000017510000000127315125206537021250 0ustar nileshnileshfiletype: gomod detect: filename: "go.mod" rules: # URL - type: "(^|[ \\t])+\\b([a-zA-Z0-9-]+\\.?)+(/[a-zA-Z0-9-_\\.]+)*\\b" # Keywords - special: "(^|[ \\t])+\\b(module|go)\\b" - preproc: "(^|[ \\t])+\\b(toolchain|require|exclude|replace|retract)\\b" - symbol.operator: "=>" # Brackets - type: "(\\(|\\))" # Go version - type: "(^|[ \\t])+([0-9]+\\.?)+" # Version - constant.string: "(^|[ \\t])+v([0-9]+\\.?){3}.*" - constant.number: "(^|[ \\t])+v([0-9]+\\.?){3}" - comment: start: "//" end: "$" rules: - todo: "(indirect):?" # (^|[ \\t])+ means after start of string or space or tab character zyedidia-micro-6a62575/runtime/syntax/golo.yaml0000664000175000017510000001001615125206537021076 0ustar nileshnileshfiletype: golo detect: filename: "\\.golo$" rules: - type: "\\b(function|fun|)\\b" - type: "\\b(struct|DynamicObject|union|AdapterFabric|Adapter|DynamicVariable|Observable)\\b" - type: "\\b(list|set|array|vector|tuple|map)\\b" - type: "\\b(Ok|Error|Empty|None|Some|Option|Result|Result.ok|Result.fail|Result.error|Result.empty|Optional.empty|Optional.of)\\b" - identifier.class: "\\b(augment|pimp)\\b" - identifier.class: "\\b(interfaces|implements|extends|overrides|maker|newInstance)\\b" - identifier.class: "\\b(isEmpty|isNone|isPresent|isSome|iterator|flattened|toList|flatMap|`and|orElseGet|`or|toResult|apply|either)\\b" - identifier.class: "\\b(result|option|trying|raising|nullify|catching)\\b" - identifier.class: "\\b(promise|setFuture|failedFuture|all|any)\\b" - identifier.class: "\\b(initialize|initializeWithinThread|start|future|fallbackTo|onSet|onFail|cancel|enqueue)\\b" - identifier.class: "\\b(println|print|raise|readln|readPassword|secureReadPassword|requireNotNull|require|newTypedArray|range|reversedRange|mapEntry|asInterfaceInstance|asFunctionalInterface|isClosure|fileToText|textToFile|fileExists|currentDir|sleep|uuid|isArray|arrayTypeOf|charValue|intValue|longValue|doubleValue|floatValue|removeByIndex|box)\\b" - identifier.class: "\\b(likelySupported|reset|bold|underscore|blink|reverse_video|concealed|fg_black|fg_red|fg_green|fg_yellow|fg_blue|fg_magenta|fg_cyan|fg_white|bg_black|bg_red|bg_green|bg_yellow|bg_blue|bg_magenta|bg_cyan|bg_white|cursor_position|cursor_save_position|cursor_restore_position|cursor_up|cursor_down|cursor_forward|cursor_backward|erase_display|erase_line)\\b" - identifier.class: "\\b(emptyList|cons|lazyList|fromIter|generator|repeat|iterate)\\b" - identifier.class: "\\b(asLazyList|foldl|foldr|take|takeWhile|drop|dropWhile|subList)\\b" - identifier.class: "\\b(import)\\b" - identifier.class: "\\b(module)\\b" - identifier.class: "\\b(JSON)\\b" - identifier.class: "\\b(stringify|parse|toJSON|toDynamicObject|updateFromJSON)\\b" - identifier.class: "\\b(newInstance|define|getKey|getValue|properties|fallback)\\b" - identifier.class: "\\b(times|upTo|downTo)\\b" - identifier.class: "\\b(format|toInt|toInteger|toDouble|toFloat|toLong)\\b" - identifier.class: "\\b(head|tail|isEmpty|reduce|each|count|exists)\\b" - identifier.class: "\\b(newWithSameType|destruct|append|add|addIfAbsent|prepend|insert|last|unmodifiableView|find|filter|map|join|reverse|reversed|order|ordered|removeAt|include|exclude|remove|delete|has|contains|getOrElse|toArray)\\b" - identifier.class: "\\b(add|addTo|succ|pred|mul|neg|sub|rsub|div|rdiv|mod|rmod|pow|rpow|str|lt|gt|eq|ne|ge|le|`and|`or|`not|xor|even|odd|contains|isEmpty|`is|`isnt|`oftype|`orIfNull|fst|snd|getitem|setitem|getter|id|const|False|True|Null|curry|uncurry|unary|spreader|varargs|swapArgs|swapCurry|swapCouple|swap|invokeWith|pipe|compose|io|andThen|until|recur|cond)\\b" - identifier.class: "\\b(toUpperCase|equals|startsWith)\\b" - statement: "\\b(if|else|then|when|case|match|otherwise)\\b" - special: "\\b(with|break|continue|return)\\b" - error: "\\b(try|catch|finally|throw)\\b" - identifier: "\\b(super|this|let|var|local)\\b" - symbol.brackets: "[(){}]|\\[|\\]" - statement: "\\b(for|while|foreach|in)\\b" - constant: "\\b(and|in|is|not|or|isnt|orIfNull)\\b" - constant.bool: "\\b(true|false)\\b" - constant: "\\b(null|undefined)\\b" - symbol.operator: "[\\-+/*=<>!~%&|^]|:=" - constant.number: "\\b([0-9]+|0x[0-9a-fA-F]*)\\b|'.'" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "----" end: "----" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/godoc.yaml0000664000175000017510000000040515125206537021232 0ustar nileshnilesh# godoc # example: go doc -all | micro filetype: godoc detect: filename: "\\.godoc$" header: package.*import rules: - preproc: "^[^ ].*" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/go.yaml0000664000175000017510000000344615125206537020554 0ustar nileshnileshfiletype: go detect: filename: "\\.go$" rules: # Conditionals and control flow - special: "\\b(break|case|continue|default|go|goto|range|return|println|fallthrough)\\b" - statement: "\\b(else|for|if|switch|select)\\b" - preproc: "\\b(package|import|const|var|type|struct|func|defer|iota|make|new|copy|len|cap|panic|append|close|delete|print|recover)\\b" - symbol.operator: "[-+/*=<>!~%&|^]|:=" # Types - symbol: "(,|\\.)" - type: "\\b(u?int(8|16|32|64)?|float(32|64)|complex(64|128))\\b" - type: "\\b(uintptr|byte|rune|string|interface|bool|map|chan|error)\\b" - type.keyword: "\\b(struct)\\b" - constant.bool: "\\b(true|false|nil)\\b" # Brackets - symbol.brackets: "(\\{|\\})" - symbol.brackets: "(\\(|\\))" - symbol.brackets: "(\\[|\\])" # Numbers and strings - constant.number: "\\b([0-9]+|0x[0-9a-fA-F]*)\\b|'.'" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - error: "..+" - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - constant.string: start: "`" end: "`" rules: [] - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/gnuplot.yaml0000664000175000017510000000053315125206537021631 0ustar nileshnileshfiletype: gnuplot detect: filename: "\\.(gnu|gpi|plt|gp)$" rules: - statement: "\\b(set|unset|plot|splot|replot|if|else|do|for|while|fit)\\b" - symbol.operator: "[-+/*=<>?:!~%&|^$]" - constant.number: "\\b([0-9]+|0x[0-9a-fA-F]*)\\b" - comment: start: "#" end: "$" rules: - todo: "TODO:?" zyedidia-micro-6a62575/runtime/syntax/glsl.yaml0000664000175000017510000000173515125206537021107 0ustar nileshnileshfiletype: glsl detect: filename: "\\.(frag|vert|fp|vp|glsl)$" rules: - identifier: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[()]" - type: "\\b(void|bool|bvec2|bvec3|bvec4|int|ivec2|ivec3|ivec4|float|vec2|vec3|vec4|mat2|mat3|mat4|struct|sampler1D|sampler2D|sampler3D|samplerCUBE|sampler1DShadow|sampler2DShadow)\\b" - identifier: "\\bgl_(DepthRangeParameters|PointParameters|MaterialParameters|LightSourceParameters|LightModelParameters|LightModelProducts|LightProducts|FogParameters)\\b" - statement: "\\b(const|attribute|varying|uniform|in|out|inout|if|else|return|discard|while|for|do)\\b" - statement: "\\b(break|continue)\\b" - constant.bool: "\\b(true|false)\\b" - symbol.operator: "[-+/*=<>?:!~%&|^]" - constant.number: "\\b([0-9]+|0x[0-9a-fA-F]*)\\b" - comment: start: "//" end: "$" rules: - todo: "TODO:?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "TODO:?" zyedidia-micro-6a62575/runtime/syntax/git-rebase-todo.yaml0000664000175000017510000000076515125206537023135 0ustar nileshnileshfiletype: git-rebase-todo detect: filename: "^(.*[\\/])?git\\-rebase\\-todo$" rules: # Rebase commands - statement: "^(p(ick)?|r(eword)?|e(dit)?|s(quash)?|f(ixup)?|x|exec|b(reak)?|d(rop)?|l(abel)?|t|reset|m(erge)?)\\b" # Commit IDs - identifier: "\\b([0-9a-fA-F]{7,40})\\b" # Color keywords for Github (and others) - type.keyword: "\\b(?i)((fix(es|ed)?|close(s|d)?) #[0-9]+)\\b" # Comments - comment.line: start: "^#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/git-config.yaml0000664000175000017510000000051415125206537022166 0ustar nileshnileshfiletype: git-config detect: filename: "git(config|modules)$|\\.git/config$" rules: - constant: "\\<(true|false)\\>" - type.keyword: "^[[:space:]]*[^=]*=" - constant: "^[[:space:]]*\\[.*\\]$" - constant: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'" - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/git-commit.yaml0000664000175000017510000000225215125206537022212 0ustar nileshnileshfiletype: git-commit detect: filename: "^(.*[\\/])?(COMMIT_EDITMSG|TAG_EDITMSG|MERGE_MSG)$" rules: # File changes - type.keyword: "#[[:space:]](deleted|modified|new file|renamed):[[:space:]].*" - type.keyword: "#[[:space:]]deleted:" - type.keyword: "#[[:space:]]modified:" - type.keyword: "#[[:space:]]new file:" - type.keyword: "#[[:space:]]renamed:" - type.keyword: "^#[[:space:]]Changes.*[:]" - type.keyword: "^#[[:space:]]Your branch and '[^']+" - type.keyword: "^#[[:space:]]Your branch and '" - type.keyword: "^#[[:space:]]On branch [^ ]+" - type.keyword: "^#[[:space:]]On branch" # Color keywords for closing issues (such as on Github) - type.keyword: "\\b(?i)((fix(es|ed)?|close(s|d)?) #[0-9]+)\\b" # Comments - comment.line: start: "^#" end: "$" rules: [] # Diffs (i.e. git commit --verbose) - default: start: "^diff --git" # Diff output puts a space before file contents on each line so this # should never match valid diff output and extend highlighting to the # end of the file end: "^ENDOFFILE" rules: - include: "patch" zyedidia-micro-6a62575/runtime/syntax/gentoo-etc-portage.yaml0000664000175000017510000000126615125206537023650 0ustar nileshnileshfiletype: etc-portage detect: filename: "\\.(keywords|mask|unmask|use)(/.+)?$" rules: # Use flags: - constant.bool.false: "[[:space:]]+\\+?[a-zA-Z0-9_-]+" - constant.bool.true: "[[:space:]]+-[a-zA-Z0-9_-]+" # Likely version numbers: - special: "-[[:digit:]].*([[:space:]]|$)" # Accepted arches: - identifier.class: "[~-]?\\b(alpha|amd64|arm|hppa|ia64|mips|ppc|ppc64|s390|sh|sparc|x86|x86-fbsd)\\b" - identifier.class: "[[:space:]][~-]?\\*" # Categories: - statement: "^[[:space:]]*.*/" # Masking regulators: - symbol: "^[[:space:]]*(=|~|<|<=|=<|>|>=|=>)" # Comments: - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/gentoo-ebuild.yaml0000664000175000017510000000423215125206537022676 0ustar nileshnileshfiletype: ebuild detect: filename: "\\.e(build|class)$" rules: # All the standard portage functions - identifier: "^src_(unpack|compile|install|test)|^pkg_(config|nofetch|setup|(pre|post)(inst|rm))" # Highlight bash related syntax - statement: "\\b(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while|continue|break)\\b" - statement: "(\\{|\\}|\\(|\\)|\\;|\\]|\\[|`|\\\\|\\$|<|>|!|=|&|\\|)" - statement: "-(e|d|f|r|g|u|w|x|L)\\b" - statement: "-(eq|ne|gt|lt|ge|le|s|n|z)\\b" # Highlight variables ... official portage ones in red, all others in bright red - preproc: "\\$\\{?[a-zA-Z_0-9]+\\}?" - special: "\\b(ARCH|HOMEPAGE|DESCRIPTION|IUSE|SRC_URI|LICENSE|SLOT|KEYWORDS|FILESDIR|WORKDIR|(P|R)?DEPEND|PROVIDE|DISTDIR|RESTRICT|USERLAND)\\b" - special: "\\b(S|D|T|PV|PF|P|PN|A)\\b|\\bC(XX)?FLAGS\\b|\\bLDFLAGS\\b|\\bC(HOST|TARGET|BUILD)\\b" # Highlight portage commands - identifier: "\\buse(_(with|enable))?\\b [!a-zA-Z0-9_+ -]*|inherit.*" - statement: "\\be(begin|end|conf|install|make|warn|infon?|error|log|patch|new(group|user))\\b" - statement: "\\bdie\\b|\\buse(_(with|enable))?\\b|\\binherit\\b|\\bhas\\b|\\b(has|best)_version\\b|\\bunpack\\b" - statement: "\\b(do|new)(ins|s?bin|doc|lib(\\.so|\\.a)|man|info|exe|initd|confd|envd|pam|menu|icon)\\b" - statement: "\\bdo(python|sed|dir|hard|sym|html|jar|mo)\\b|\\bkeepdir\\b" - statement: "prepall(docs|info|man|strip)|prep(info|lib|lib\\.(so|a)|man|strip)" - statement: "\\b(doc|ins|exe)into\\b|\\bf(owners|perms)\\b|\\b(exe|ins|dir)opts\\b" # Highlight common commands used in ebuilds - type: "\\bmake\\b|\\b(cat|cd|chmod|chown|cp|echo|env|export|grep|let|ln|mkdir|mv|rm|sed|set|tar|touch|unset)\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/gemini.yaml0000664000175000017510000000060415125206537021410 0ustar nileshnileshfiletype: gemini detect: filename: "\\.(gmi|gemini)$" rules: # link lines - constant: "^=>[[:space:]].*" # preformatted text lines - special: start: "^```" end: "^```" rules: [] # heading lines - special: "^#{1,3}.*" # unordered list items - identifier: "^\\*[[:space:]]" # quote lines - statement: "^>.*" zyedidia-micro-6a62575/runtime/syntax/gdscript.yaml0000664000175000017510000000445315125206537021765 0ustar nileshnileshfiletype: gdscript detect: filename: "\\.gd$" rules: # Built-in constants - constant: "\\b(INF|NAN|PI|TAU)\\b" - constant.bool: "\\b(null|true|false)\\b" # Built-in functions - identifier: "\\b(abs|acos|asin|atan|atan2|ceil|clamp|convert|cos|cosh|db2linear|decimals|deg2rad|ease|exp|float|floor|fmod|fposmod|hash|int|isinf|isnan|lerp|linear2db|load|log|max|min|nearest_po2|pow|preload|print|printerr|printraw|prints|printt|rad2deg|rand_range|rand_seed|randomize|randi|randf|range|round|seed|sin|slerp|sqrt|str|str2var|tan|typeof|var2str|weakref)\\b" # Built-in node names - identifier: "\\b(AnimationPlayer|AnimationTreePlayer|Button|Control|Engine|HTTPClient|HTTPRequest|Input|InputEvent|MainLoop|Node|Node2D|OS|SceneTree|Spatial|StreamPeer|PacketPeer|PacketPeerUDP|Timer|Tween)\\b" # Types - type: "\\b(AABB|Array|Basis|Color|Dictionary|NodePath|Object|Plane|PoolByteArray|PoolColorArray|PoolIntArray|PoolRealArray|PoolVector2Array|PoolVector3Array|Quat|Rect2|RID|String|Transform|Transform2D|Vector2|Vector3)\\b" # Definitions - identifier: "func [a-zA-Z_0-9]+" # Keywords - statement: "\\b(and|as|assert|break|breakpoint|class|const|continue|elif|else|enum|export|extends|for|func|if|in|is|map|master|mastersync|match|not|onready|or|pass|remote|remotesync|return|self|setget|slave|slavesync|signal|sync|tool|var|while|yield)\\b" # Operators - statement: "[.:;,+*|=!\\%@]|<|>|/|-|&" # Parentheses - statement: "[(){}]|\\[|\\]" # Numbers - constant: "\\b[0-9]+\\b" - constant.number: "\\b([0-9]+|0x[0-9a-fA-F]*)\\b|'.'" - comment: start: "\"\"\"" end: "\"\"\"" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "'''" end: "'''" rules: - todo: "(TODO|XXX|FIXME):?" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/fsharp.yaml0000664000175000017510000000333415125206537021426 0ustar nileshnileshfiletype: fsharp detect: filename: "\\.fs?$" rules: - identifier: "\\b[A-Z][0-9a-z_]{2,}\\b" #declarations - statement: "\\b(let|val|method|in|and|rec|private|virtual|constraint)\\b" #structure items - type: "\\b(type|open|class|module|exception|external)\\b" #patterns - statement: "\\b(fun|function|functor|match|try|with)\\b" #patterns-modifiers - statement: "\\b(as|when|of)\\b" #conditions - statement: "\\b(if|then|else)\\b" #blocs - type: "\\b(begin|end|object|struct|sig|for|while|do|done|to|downto)\\b" #constantes - constant.bool: "\\b(true|false)\\b" #modules/classes - special: "\\b(include|inherit|initializer)\\b" #expr modifiers - special: "\\b(new|ref|mutable|lazy|assert|raise)\\b" #keywords which don't exist in ocaml - type: "\\b(base|delegate|downcast|extern|finally|fixed|global|inline|interface|internal|let!|member|namespace|null|override|private|public)\\b" - type: "\\b(return|return!|select|static|upcast|use|use!|void|yield|yield!)\\b" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - comment: start: "\\(\\*" end: "\\*\\)" rules: [] zyedidia-micro-6a62575/runtime/syntax/freebsd-kernel.yaml0000664000175000017510000000041615125206537023031 0ustar nileshnileshfiletype: freebsd-kernel detect: filename: "GENERIC$" rules: - identifier: "^(cpu|ident|options|makeoptions|device|include)" - statement: "\\s\\S*" - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/fortran.yaml0000664000175000017510000000543615125206537021623 0ustar nileshnileshfiletype: fortran detect: filename: "\\.([Ff]|[Ff]90|[Ff]95|[Ff][Oo][Rr])$" rules: - type: "(?i)\\b(action|advance|all|allocatable|allocated|any|apostrophe)\\b" - type: "(?i)\\b(append|asis|assign|assignment|associated|bind|character|common)\\b" - type: "(?i)\\b(complex|data|default|delim|dimension|double precision)\\b" - type: "(?i)\\b(elemental|enum|enumerator|epsilon|external|file|fmt|form|format|huge)\\b" - type: "(?i)\\b(implicit|include|index|inquire|integer|intent|interface)\\b" - type: "(?i)\\b(intrinsic|iostat|kind|logical|module|none|null|only)\\\\b" - type: "(?i)\\b(operator|optional|pack|parameter|pointer|position|private)\\b" - type: "(?i)\\b(program|public|real|recl|recursive|selected_int_kind)\\b" - type: "(?i)\\b(selected_real_kind|subroutine|status|module|function|logical)\\b" - constant: "(?i)\\b(abs|achar|adjustl|adjustr|allocate|bit_size|call|char)\\b" - constant: "(?i)\\b(close|contains|count|cpu_time|cshift|date_and_time)\\b" - constant: "(?i)\\b(deallocate|digits|dot_product|eor|eoshift|iachar)\\b" - constant: "(?i)\\b(iand|ibclr|ibits|ibset|ichar|ieor|iolength|ior|ishft|ishftc)\\b" - constant: "(?i)\\b(lbound|len|len_trim|matmul|maxexponent|maxloc|maxval|merge)\\b" - constant: "(?i)\\b(minexponent|minloc|minval|mvbits|namelist|nearest|nullify)\\b" - constant: "(?i)\\b(open|pad|present|print|product|pure|quote|radix)\\b" - constant: "(?i)\\b(random_number|random_seed|range|read|readwrite|replace)\\b" - constant: "(?i)\\b(reshape|rewind|save|scan|sequence|shape|sign|size|spacing)\\b" - constant: "(?i)\\b(spread|sum|system_clock|target|transfer|transpose|trim)\\b" - constant: "(?i)\\b(ubound|unpack|verify|write|tiny|type|use|yes|true|false|not)\\b" - constant.number: "\\b([0-9]+)\\b" - statement: "(?i)\\b(.and.|case|do|else|else?if|else?where|end|end?do|end?if)\\b" - statement: "(?i)\\b(end?select|.eqv.|forall|if|lge|lgt|lle|llt|.neqv.|.not.)\\b" - statement: "(?i)\\b(or|and|repeat|select|case|then|where|while|import)\\b" - special: "(?i)\\b(continue|cycle|exit|go?to|result|return)\\b" #Operator Color - symbol.operator: "[.:;,+*|=!\\%]|/|-|>|<|&" #Parenthetical Color - symbol.bracket: "[(){}]|\\[|\\]" # Add preprocessor commands. - preproc: "^[[:space:]]*#[[:space:]]*(define|include|(un|ifn?)def|endif|el(if|se)|if|warning|error)" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "!" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/forth.yaml0000664000175000017510000000147315125206537021267 0ustar nileshnileshfiletype: forth detect: filename: "\\.(forth|4th|fs|fs8|ft|fth|frt)$" rules: - identifier: "\\b[A-Za-z_0-9-]*\\b" - statement: "\\b(?i:(if|else|then|do|loop|case|endcase|of|endof|begin|while|repeat|until|again|unloop|leave|exit|done|next|\\?do|\\+do|\\-do|\\+loop|\\-loop|\\?leave))\\b" - statement: "(^:|;$)" - type: "\\b(?i:(variable|constant|cells))\\b" - special: "\\B[?.]\\B" #for some reason, \b and \B are inverted for symbols - constant.number: "\\b[0-9]+\\b" - constant.string: start: "\\b([Ss.]\" )" end: "\"" rules: [] - comment: start: "\\(" end: "\\)" rules: - todo: "(TODO|NOTE|XXX|FIXME):?" - comment: start: "\\\\" end: "$" rules: - todo: "(TODO|NOTE|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/fish.yaml0000664000175000017510000000377415125206537021104 0ustar nileshnileshfiletype: fish detect: filename: "\\.fish$" header: "^#!.*/(env +)?fish( |$)" rules: # Numbers - constant: "\\b[0-9]+\\b" # Conditionals and control flow - statement: "\\b(and|begin|break|case|continue|else|end|for|function|if|in|not|or|return|select|shift|switch|while)\\b" - special: "(\\{|\\}|\\(|\\)|\\;|\\]|\\[|`|\\\\|\\$|<|>|^|!|=|&|\\|)" # Fish commands - type: "\\b(bg|bind|block|breakpoint|builtin|cd|count|command|commandline|complete|dirh|dirs|echo|emit|eval|exec|exit|fg|fish|fish_config|fish_ident|fish_pager|fish_prompt|fish_right_prompt|fish_update_completions|fishd|funced|funcsave|functions|help|history|jobs|math|mimedb|nextd|open|popd|prevd|psub|pushd|pwd|random|read|set|set_color|source|status|string|trap|type|ulimit|umask|vared)\\b" # Common linux commands - type: "\\b((g|ig)?awk|bash|dash|find|\\w{0,4}grep|kill|killall|\\w{0,4}less|make|pkill|sed|sh|tar)\\b" # Coreutils commands - type: "\\b(base64|basename|cat|chcon|chgrp|chmod|chown|chroot|cksum|comm|cp|csplit|cut|date|dd|df|dir|dircolors|dirname|du|env|expand|expr|factor|false|fmt|fold|head|hostid|id|install|join|link|ln|logname|ls|md5sum|mkdir|mkfifo|mknod|mktemp|mv|nice|nl|nohup|nproc|numfmt|od|paste|pathchk|pinky|pr|printenv|printf|ptx|pwd|readlink|realpath|rm|rmdir|runcon|seq|(sha1|sha224|sha256|sha384|sha512)sum|shred|shuf|sleep|sort|split|stat|stdbuf|stty|sum|sync|tac|tail|tee|test|time|timeout|touch|tr|true|truncate|tsort|tty|uname|unexpand|uniq|unlink|users|vdir|wc|who|whoami|yes)\\b" # Conditional flags - statement: "--[a-z-]+" - statement: "\\ -[a-z]+" - identifier: "(?i)\\{?\\$[0-9A-Z_!@#$*?-]+\\}?" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: [] - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/erlang.yaml0000664000175000017510000000532615125206537021416 0ustar nileshnileshfiletype: erlang detect: filename: "\\.erl$" rules: - identifier: "\\b[A-Z][0-9a-z_]*\\b" # See: https://erlang.org/doc/reference_manual/data_types.html - constant.number: "\\b[0-9]+(\\.[0-9]+)?(e-?[0-9]+)?\\b" - constant.number: "\\b[0-9]{1,2}\\#[a-zA-Z0-9]+\\b" - constant.bool: "\\b(true|false)\\b" - constant.number: "\\$\\\\?\\S{1}" # See: https://erlang.org/doc/reference_manual/introduction.html - statement: "\\b(after|and|andalso|band|begin|bnot|bor|bsl|bsr|bxor|case|catch|cond|div|end|fun|if|let|not|of|or|orelse|receive|rem|try|when|xor)\\b" # See: https://erlang.org/doc/reference_manual/macros.html - preproc: "\\-(module|export|record|include|include_lib|define|undef|ifdef|ifndef|else|endif|if|elif|error|warning)\\b" - identifier.macro: "\\?[A-Z0-9_]+\\b" # See: https://erlang.org/doc/man/erlang.html - special: "\\b(ext_binary|binary|iovec|message_queue_data|time(_unit|stamp)|abs|apply|atom(_to_binary|_to_list)|binary_(part|to_atom|to_existing_atom|to_float|to_integer|to_list|to_term)|bit(_size|string_to_list)|byte_size|ceil|check_(old_code|process_code)|date|delete_module|demonitor|disconnect_node|element|erase|error|exit|float(_to_binary|_to_list)?|floor|garbage_collect|get|group_leader|halt|integer(_to_binary|to_list)|iolist_(size|to_binary)|is_(alive|atom|binary|bitstring|boolean|float|function|integer|list|map|map_key|number|pid|port|process_alive|record|reference|tuple|length)|link|list_to_(atom|binary|bitstring|existing_atom|float|integer|pid|port|ref|tuple)|load_module|make_ref|map_(get|size)|max|min|module_loaded|monitor(_node)?|nodes?|now|open_port|pid_to_list|port(_close|command|connect|control|to_list)|pre_loaded|process(_flag|_info|es)|purge_module|put|register(ed)?|round|self|setelement|size|spawn(_link|_monitor|_opt|_binary)?|statistics|trunc|tuple_(size|to_list)|unlink|unregister|whereis)\\b" # See: https://erlang.org/doc/reference_manual/data_types.html#atom - symbol: start: "'" end: "'" skip: "\\\\." rules: [] # - constant.specialChar: "%." # - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" # - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - comment: start: "\\(\\*" end: "\\*\\)" rules: - todo: "(TODO|FIXME|WONTFIX|NOTE|HACK):?" - comment: start: "%" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/erb.yaml0000664000175000017510000000456015125206537020715 0ustar nileshnileshfiletype: erb detect: filename: "\\.erb$|\\.rhtml$" rules: - error: "<[^!].*?>" - symbol.tag: "(?i)<[/]?(a(bbr|cronym|ddress|pplet|rea|rticle|side|udio)?|b(ase(font)?|d(i|o)|ig|lockquote|r)?|ca(nvas|ption)|center|cite|co(de|l|lgroup)|d(ata(list)?|d|el|etails|fn|ialog|ir|l|t)|em(bed)?|fieldset|fig(caption|ure)|font|form|(i)?frame|frameset|h[1-6]|hr|i|img|in(put|s)|kbd|keygen|label|legend|li(nk)?|ma(in|p|rk)|menu(item)?|met(a|er)|nav|no(frames|script)|o(l|pt(group|ion)|utput)|p(aram|icture|re|rogress)?|q|r(p|t|uby)|s(trike)?|samp|se(ction|lect)|small|source|span|strong|su(b|p|mmary)|textarea|time|track|u(l)?|var|video|wbr)( .*|>)*?>" - symbol.tag.extended: "(?i)<[/]?(body|div|html|head(er)?|footer|title|table|t(body|d|h(ead)?|r|foot))( .*|>)*?>" - preproc: "(?i)<[/]?(script|style)( .*|>)*?>" - special: "&[^;[[:space:]]]*;" - symbol: "[:=]" - identifier: "(alt|bgcolor|height|href|id|label|longdesc|name|onclick|onfocus|onload|onmouseover|size|span|src|style|target|type|value|width)=" - constant.string: "\"[^\"]*\"" - constant.number: "(?i)#[0-9a-fA-F]{6,6}" - constant.string.url: "(ftp(s)?|http(s)?|git|chrome)://[^ ]+" - comment: "" - preproc: "" - default: start: "<%" end: "%>" rules: [] - preproc: "<%|%>" - red: "&[^;[[:space:]]]*;" - statement: "\\b(BEGIN|END|alias|and|begin|break|case|class|def|defined\\?|do|else|elsif|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield)\\b" - identifier.var: "(\\$|@|@@)?\\b[A-Z]+[0-9A-Z_a-z]*" - magenta: "(?i)([ ]|^):[0-9A-Z_]+\\b" - identifier.macro: "\\b(__FILE__|__LINE__)\\b" - brightmagenta: "!/([^/]|(\\\\/))*/[iomx]*|%r\\{([^}]|(\\\\}))*\\}[iomx]*" - brightblue: "`[^`]*`|%x\\{[^}]*\\}" - constant.string: "\"([^\"]|(\\\\\"))*\"|%[QW]?\\{[^}]*\\}|%[QW]?\\([^)]*\\)|%[QW]?<[^>]*>|%[QW]?\\[[^]]*\\]|%[QW]?\\$[^$]*\\$|%[QW]?\\^[^^]*\\^|%[QW]?![^!]*!" - brightgreen: "#\\{[^}]*\\}" - green: "'([^']|(\\\\'))*'|%[qw]\\{[^}]*\\}|%[qw]\\([^)]*\\)|%[qw]<[^>]*>|%[qw]\\[[^]]*\\]|%[qw]\\$[^$]*\\$|%[qw]\\^[^^]*\\^|%[qw]![^!]*!" - comment: "#[^{].*$|#$" - comment.bright: "##[^{].*$|##$" - identifier.macro: start: "<<-?'?EOT'?" end: "^EOT" rules: [] - todo: "(XXX|TODO|FIXME|\\?\\?\\?)" zyedidia-micro-6a62575/runtime/syntax/elm.yaml0000664000175000017510000000163415125206537020721 0ustar nileshnileshfiletype: elm detect: filename: "\\.elm$" rules: - statement: "\\b(as|alias|case|else|exposing|if|import|in|let|module|of|port|then|type|)\\b" - statement: "(\\=|\\:|\\->)" - type: "\\b([A-Z][A-Za-z\\d]*)\\b" - identifier: "^([a-z][A-Za-z\\d]*)\\b" - constant.string: start: "\"\"\"" end: "\"\"\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "--" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "\\{-" end: "-\\}" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/elixir.yaml0000664000175000017510000000343015125206537021434 0ustar nileshnileshfiletype: elixir detect: filename: "\\.ex$|\\.exs$" rules: - statement: "\\b(abs|trunc|rem|div|round|max|min|and|or|not|throw|raise|reraise|hd|tl|in|length|elem|put_elem|destructure|to_(string|charlist)|is_(atom|binary|bitstring|boolean|float|function|integer|list|map|nil|number|pid|port|reference|tuple)|(bit|byte|map|tuple)_size|binary_part|def(delegate|exception|guard|guardp|impl|macro|macrop|module|overridable|p|protocol|struct)?|sigil_[crswCRSWDNT]|if|else|unless|cond|binding|node|self|spawn|spawn_link|spawn_monitor|send|exit|struct|get_and_update_in|get_in|put_in|pop_in|update_in|apply|inspect|make_ref|use|do|end)\\b" - statement: "\\b(alias|import|require|case|fn|receive|after|try|catch|rescue|super|quote|unquote|unquote_splicing|for|with)\\b" - constant: "\\b\\[A-Z]+\\b" - constant.number: "\\b[0-9]+\\b" - constant.string: "`[^`]*`|%x\\{[^}]*\\}" - constant.string: "\"([^\"]|(\\\\\"))*\"|%[QW]?\\{[^}]*\\}|%[QW]?\\([^)]*\\)|%[QW]?<[^>]*>|%[QW]?\\[[^]]*\\]|%[QW]?\\$[^$]*\\$|%[QW]?\\^[^^]*\\^|%[QW]?![^!]*!" - constant.string: "'([^']|(\\\\'))*'|%[qw]\\{[^}]*\\}|%[qw]\\([^)]*\\)|%[qw]<[^>]*>|%[qw]\\[[^]]*\\]|%[qw]\\$[^$]*\\$|%[qw]\\^[^^]*\\^|%[qw]![^!]*!" - symbol.brackets: "\\{|\\}|\\[|\\]|\\(|\\)" - comment: "#[^{].*$|#$" - comment.bright: "##[^{].*$|##$" - type.keyword: "\\:[a-zA-Z][a-zA-Z0-9_]*" - type.keyword: "\\b(describe|test)" - statement: "\\b(expected|assert|assert_raise|assert_in_delta|assert_received|catch_error|catch_throw|flunk|refute|refute_in_delta|refute_received)\\b" - symbol.tag: "^\\s*\\@[a-zA-Z][a-zA-Z0-9_]*\\b" - identifier.macro: "\\b(__CALLER__|__DIR__|__ENV__|__MODULE__|__aliases__|__block__|defmacro)\\b" - todo: "(XXX|TODO|FIXME|\\?\\?\\?)" - preproc.shebang: "\\W*#!.+?( |$)" zyedidia-micro-6a62575/runtime/syntax/dot.yaml0000664000175000017510000000166115125206537020732 0ustar nileshnileshfiletype: dot detect: filename: "\\.(dot|gv)$" rules: - type: "\\b(digraph|edge|graph|node|subgraph)\\b" - statement: "\\b(arrow(head|size|tail)|(bg|fill|font)?color|center|constraint|decorateP|dir|distortion|font(name|size)|head(clip|label)|height|label(angle|distance|font(color|name|size))?|layer(s)?|margin|mclimit|minlen|name|nodesep|nslimit|ordering|orientation|page(dir)?|peripheries|port_label_distance|rank(dir|sep)?|ratio|regular|rotate|same(head|tail)|shape(file)?|sides|size|skew|style|tail(clip|label)|URL|weight|width)\\b" - symbol: "=|->|--" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/dockerfile.yaml0000664000175000017510000000146215125206537022252 0ustar nileshnileshfiletype: dockerfile detect: filename: "((Docker|Container)file[^/]*$|\\.(docker|container)file$)" rules: ## Keywords - type.keyword: "(?i)^(FROM|MAINTAINER|RUN|CMD|LABEL|EXPOSE|ENV|ADD|COPY|ENTRYPOINT|VOLUME|USER|WORKDIR|ONBUILD|ARG|HEALTHCHECK|STOPSIGNAL|SHELL)[[:space:]]" ## Brackets & parenthesis - statement: "(\\(|\\)|\\[|\\])" ## Double ampersand - special: "&&" ## Comments - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." zyedidia-micro-6a62575/runtime/syntax/default.yaml0000664000175000017510000000026415125206537021566 0ustar nileshnileshfiletype: unknown detect: filename: "" rules: # Mails - special: "[[:alnum:].%_+-]+@[[:alnum:].-]+" # URLs - identifier: "(https?|ftp|ssh)://\\S*[^])>\\s,.]" zyedidia-micro-6a62575/runtime/syntax/dart.yaml0000664000175000017510000000261215125206537021073 0ustar nileshnileshfiletype: dart detect: filename: "\\.dart$" rules: - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b" - constant.number: "\\b[-+]?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?" - constant.number: "\\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?" - identifier: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]" - statement: "\\b(break|case|catch|continue|default|else|finally)\\b" - statement: "\\b(for|function|get|if|in|as|is|new|return|set|switch|final|await|async|sync)\\b" - statement: "\\b(switch|this|throw|try|var|void|while|with|import|library|part|const|export)\\b" - constant: "\\b(true|false|null)\\b" - type: "\\b(List|String)\\b" - type: "\\b(int|num|double|bool)\\b" - statement: "[-+/*=<>!~%?:&|]" - constant: "/[^*]([^/]|(\\\\/))*[^\\\\]/[gim]*" - constant: "\\\\[0-7][0-7]?[0-7]?|\\\\x[0-9a-fA-F]+|\\\\[bfnrt'\"\\?\\\\]" - comment: start: "//" end: "$" rules: - todo: "TODO:?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "TODO:?" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." zyedidia-micro-6a62575/runtime/syntax/d.yaml0000664000175000017510000001035215125206537020364 0ustar nileshnileshfiletype: d detect: filename: "\\.(d(i|d)?)$" rules: # Operators and punctuation - statement: "(\\*|/|%|\\+|-|>>|<<|>>>|&|\\^(\\^)?|\\||~)?=" - statement: "\\.\\.(\\.)?|!|\\*|&|~|\\(|\\)|\\[|\\]|\\\\|/|\\+|-|%|<|>|\\?|:|;" # Octal integer literals are deprecated - error: "(0[0-7_]*)(L[uU]?|[uU]L?)?" # Decimal integer literals - constant.number: "([0-9]|[1-9][0-9_]*)(L[uU]?|[uU]L?)?\\b" # Binary integer literals - constant: "(0[bB][01_]*)(L[uU]?|[uU]L?)?" # Decimal float literals - constant.number: "[0-9][0-9_]*\\.([0-9][0-9_]*)([eE][+-]?([0-9][0-9_]*))?[fFL]?i?" - constant.number: "[0-9][0-9_]*([eE][+-]?([0-9][0-9_]*))[fFL]?i?" - constant.number: "[^.]\\.([0-9][0-9_]*)([eE][+-]?([0-9][0-9_]*))?[fFL]?i?" - constant.number: "[0-9][0-9_]*([fFL]?i|[fF])" # Hexadecimal integer literals - constant.number: "(0[xX]([0-9a-fA-F][0-9a-fA-F_]*|[0-9a-fA-F_]*[0-9a-fA-F]))(L[uU]?|[uU]L?)?" # Hexadecimal float literals - constant.number: "0[xX]([0-9a-fA-F][0-9a-fA-F_]*|[0-9a-fA-F_]*[0-9a-fA-F])(\\.[0-9a-fA-F][0-9a-fA-F_]*|[0-9a-fA-F_]*[0-9a-fA-F])?[pP][+-]?([0-9][0-9_]*)[fFL]?i?" - constant.number: "0[xX]\\.([0-9a-fA-F][0-9a-fA-F_]*|[0-9a-fA-F_]*[0-9a-fA-F])[pP][+-]?([0-9][0-9_]*)[fFL]?i?" # Character literals - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." # Keywords # a-e - statement: "\\b(abstract|alias|align|asm|assert|auto|body|break|case|cast|catch|class|const|continue|debug|default|delegate|do|else|enum|export|extern)\\b" # f-l - statement: "\\b(false|final|finally|for|foreach|foreach_reverse|function|goto|if|immutable|import|in|inout|interface|invariant|is|lazy)\\b" # m-r - statement: "\\b(macro|mixin|module|new|nothrow|null|out|override|package|pragma|private|protected|public|pure|ref|return)\\b" # s-w - statement: "\\b(scope|shared|static|struct|super|switch|synchronized|template|this|throw|true|try|typeid|typeof|union|unittest|version|while|with)\\b" # __ - statement: "\\b(__FILE__|__MODULE__|__LINE__|__FUNCTION__|__PRETTY_FUNCTION__|__gshared|__traits|__vector|__parameters)\\b" # Deprecated keywords - error: "\\b(delete|deprecated|typedef|volatile)\\b" # Primitive types - type: "\\b(bool|byte|cdouble|cent|cfloat|char|creal|dchar|double|float|idouble|ifloat|int|ireal|long|real|short|ubyte|ucent|uint|ulong|ushort|void|wchar)\\b" # Globally defined symbols - type: "\\b(string|wstring|dstring|size_t|ptrdiff_t)\\b" # Special tokens - constant: "\\b(__DATE__|__EOF__|__TIME__|__TIMESTAMP__|__VENDOR__|__VERSION__)\\b" # String literals # DoubleQuotedString - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." # WysiwygString - constant.string: start: "r\"" end: "\"" rules: - constant.specialChar: "\\\\." - constant.string: start: "`" end: "`" rules: - constant.specialChar: "\\\\." # HexString - constant.string: start: "x\"" end: "\"" rules: - constant.specialChar: "\\\\." # DelimitedString - constant.string: start: "q\"\\(" end: "\\)\"" rules: - constant.specialChar: "\\\\." - constant.string: start: "q\"\\{" end: "q\"\\}" rules: - constant.specialChar: "\\\\." - constant.string: start: "q\"\\[" end: "q\"\\]" rules: - constant.specialChar: "\\\\." - constant.string: start: "q\"<" end: "q\">" rules: - constant.specialChar: "\\\\." - constant.string: start: "q\"[^({[<\"][^\"]*$" end: "^[^\"]+\"" rules: - constant.specialChar: "\\\\." - constant.string: start: "q\"([^({[<\"])" end: "\"" rules: - constant.specialChar: "\\\\." # Comments - comment: start: "//" end: "$" rules: [] - comment: start: "/\\*" end: "\\*/" rules: [] - comment: start: "/\\+" end: "\\+/" rules: [] zyedidia-micro-6a62575/runtime/syntax/cython.yaml0000664000175000017510000000245315125206537021450 0ustar nileshnileshfiletype: cython detect: filename: "\\.pyx$|\\.pxd$|\\.pyi$" rules: # Python Keyword Color - statement: "\\b(and|as|assert|class|def|DEF|del|elif|ELIF|else|ELSE|except|exec|finally|for|from|global|if|IF|import|in|is|lambda|map|not|or|pass|print|raise|try|while|with|yield)\\b" - special: "\\b(continue|break|return)\\b" # Cython Keyword Color - identifier.macro: "\\b(cdef|cimport|cpdef|cppclass|ctypedef|extern|include|namespace|property|struct)\\b" - type: "\\b(bint|char|double|int|public|void|unsigned)\\b" # Operator Color - symbol: "[.:;,+*|=!\\%]|<|>|/|-|&" # Parenthetical Color - symbol.brackets: "[(){}]|\\[|\\]" - constant.string: start: "\"\"\"" end: "\"\"\"" rules: - constant.specialChar: "\\\\." - constant.string: start: "'''" end: "'''" rules: - constant.specialChar: "\\\\." - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/cuda.yaml0000664000175000017510000000545615125206537021066 0ustar nileshnileshfiletype: cuda detect: filename: "(\\.cu[h]?$)" rules: - identifier: "\\b[A-Z_][0-9A-Z_]*\\b" - type: "\\b(float|double|bool|char|int|short|long|enum|void|struct|union|typedef|(un)?signed|inline)\\b" - type: "\\b(((s?size)|((u_?)?int(8|16|32|64|ptr))|char(8|16|32))_t|wchar_t)\\b" - type: "\\b[a-z_][0-9a-z_]+(_t|_T)\\b" - type: "\\b(final|override)\\b" - type.keyword: "\\b(auto|volatile|const(expr|eval|init)?|mutable|register|thread_local|static|extern|decltype|explicit|virtual)\\b" - statement: "\\b(class|namespace|template|typename|this|friend|using|public|protected|private|noexcept)\\b" - statement: "\\b(concept|requires)\\b" - statement: "\\b(import|export|module)\\b" - statement: "\\b(for|if|while|do|else|case|default|switch)\\b" - statement: "\\b(try|throw|catch|operator|new|delete|static_assert)\\b" - statement: "\\b(goto|continue|break|return)\\b" - preproc: "^[[:space:]]*#[[:space:]]*(define|pragma|include|(un|ifn?)def|endif|el(if|se)|if|warning|error)|_Pragma" # Conditionally-supported/extension keywords - statement: "\\b(asm|fortran)\\b" # GCC builtins - statement: "(__attribute__[[:space:]]*\\(\\([^)]*\\)\\)|__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__)" # CUDA specific keywords - statement: "__(global|device|host|shared)__" # Operator Color - symbol.operator: "[-+*/%=<>.:;,~&|^!?]|\\b(sizeof|alignof|typeid|(and|or|xor|not)(_eq)?|bitor|compl|bitand|(const|dynamic|reinterpret|static)_cast)\\b" # Parenthetical Color - symbol.brackets: "[(){}]|\\[|\\]" # Integer Literals - constant.number: "(\\b([1-9][0-9']*|0[0-7']*|0[Xx][0-9a-fA-F']+|0[Bb][01]+)([Uu]?[Ll][Ll]?|[Ll][Ll]?[Uu]?)?\\b)" # Decimal Floating-point Literals - constant.number: "(\\b(([0-9']*[.][0-9']+|[0-9']+[.][0-9']*)([Ee][+-]?[0-9']+)?|[0-9']+[Ee][+-]?[0-9']+)[FfLl]?\\b)" # Hexadecimal Floating-point Literals - constant.number: "(\\b0[Xx]([0-9a-zA-Z']*[.][0-9a-zA-Z']+|[0-9a-zA-Z']+[.][0-9a-zA-Z']*)[Pp][+-]?[0-9']+[FfLl]?\\b)" - constant.bool: "(\\b(true|false|NULL|nullptr)\\b)" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - error: "..+" - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/csx.yaml0000664000175000017510000000026315125206537020736 0ustar nileshnileshfiletype: csharp-script detect: filename: "\\.csx$" header: "^#!.*/(env +)?dotnet-script( |$)" rules: - include: "csharp" - preproc: "\\B(\\#!|\\#[r|load|]+\\b)" zyedidia-micro-6a62575/runtime/syntax/css.yaml0000664000175000017510000001565015125206537020737 0ustar nileshnileshfiletype: css detect: filename: "\\.(css|scss)$" rules: # Classes and IDs - statement: "(?i)." # - normal: # start: "\\{" # end: "\\}" # rules: [] # css commands - type: "(align-content|align-items|alignment-baseline|align-self|all|animation|animation-delay|animation-direction|animation-duration|animation-fill-mode|animation-iteration-count|animation-name|animation-play-state|animation-timing-function|appearance|azimuth|backdrop-filter|backface-visibility|background|background-attachment|background-blend-mode|background-clip|background-color|background-image|background-origin|background-position|background-repeat|background-size|baseline-shift|bookmark-label|bookmark-level|bookmark-state|border|border-bottom|border-bottom-color|border-bottom-left-radius|border-bottom-right-radius|border-bottom-style|border-bottom-width|border-boundary|border-collapse|border-color|border-image|border-image-outset|border-image-repeat|border-image-slice|border-image-source|border-image-width|border-left|border-left-color|border-left-style|border-left-width|border-radius|border-right|border-right-color|border-right-style|border-right-width|border-spacing|border-style|border-top|border-top-color|border-top-left-radius|border-top-right-radius|border-top-style|border-top-width|border-width|bottom|box-decoration-break|box-shadow|box-sizing|box-snap|box-suppress|break-after|break-before|break-inside|caption-side|caret|caret-animation|caret-color|caret-shape|chains|clear|clip|clip-path|clip-rule|color|color-interpolation-filters|column-count|column-fill|column-gap|column-rule|column-rule-color|column-rule-style|column-rule-width|columns|column-span|column-width|content|continue|counter-increment|counter-reset|counter-set|cue|cue-after|cue-before|cursor|direction|display|dominant-baseline|elevation|empty-cells|filter|flex|flex-basis|flex-direction|flex-flow|flex-grow|flex-shrink|flex-wrap|float|float-defer|float-offset|float-reference|flood-color|flood-opacity|flow|flow-from|flow-into|font|font-family|font-feature-settings|font-kerning|font-language-override|font-size|font-size-adjust|font-stretch|font-style|font-synthesis|font-variant|font-variant-alternates|font-variant-caps|font-variant-east-asian|font-variant-ligatures|font-variant-numeric|font-variant-position|font-weight|footnote-display|footnote-policy|gap|glyph-orientation-vertical|grid|grid-area|grid-auto-columns|grid-auto-flow|grid-auto-rows|grid-column|grid-column-end|grid-column-gap|grid-column-start|grid-gap|grid-row|grid-row-end|grid-row-gap|grid-row-start|grid-template|grid-template-areas|grid-template-columns|grid-template-rows|hanging-punctuation|height|hyphenate-character|hyphenate-limit-chars|hyphenate-limit-last|hyphenate-limit-lines|hyphenate-limit-zone|hyphens|image-orientation|image-rendering|image-resolution|initial-letter|initial-letter-align|initial-letter-wrap|isolation|justify-content|justify-items|justify-self|left|letter-spacing|lighting-color|line-break|line-grid|line-height|line-snap|list-style|list-style-image|list-style-position|list-style-type|margin|margin-bottom|margin-left|margin-right|margin-top|marker|marker-end|marker-knockout-left|marker-knockout-right|marker-mid|marker-pattern|marker-segment|marker-side|marker-start|marquee-direction|marquee-loop|marquee-speed|marquee-style|mask|mask-border|mask-border-mode|mask-border-outset|mask-border-repeat|mask-border-slice|mask-border-source|mask-border-width|mask-clip|mask-composite|mask-image|mask-mode|mask-origin|mask-position|mask-repeat|mask-size|mask-type|max-height|max-lines|max-width|min-height|min-width|mix-blend-mode|motion|motion-offset|motion-path|motion-rotation|nav-down|nav-left|nav-right|nav-up|object-fit|object-position|offset-after|offset-before|offset-end|offset-start|opacity|order|orphans|outline|outline-color|outline-offset|outline-style|outline-width|overflow|overflow-style|overflow-wrap|overflow-x|overflow-y|padding|padding-bottom|padding-left|padding-right|padding-top|page|page-break-after|page-break-before|page-break-inside|pause|pause-after|pause-before|perspective|perspective-origin|pitch|pitch-range|play-during|pointer-events|polar-anchor|polar-angle|polar-distance|polar-origin|position|presentation-level|quotes|region-fragment|resize|rest|rest-after|rest-before|richness|right|rotation|rotation-point|ruby-align|ruby-merge|ruby-position|running|scrollbar-color|scroll-behavior|scroll-snap-align|scroll-snap-margin|scroll-snap-margin-block|scroll-snap-margin-block-end|scroll-snap-margin-block-start|scroll-snap-margin-bottom|scroll-snap-margin-inline|scroll-snap-margin-inline-end|scroll-snap-margin-inline-start|scroll-snap-margin-left|scroll-snap-margin-right|scroll-snap-margin-top|scroll-snap-padding|scroll-snap-padding-block|scroll-snap-padding-block-end|scroll-snap-padding-block-start|scroll-snap-padding-bottom|scroll-snap-padding-inline|scroll-snap-padding-inline-end|scroll-snap-padding-inline-start|scroll-snap-padding-left|scroll-snap-padding-right|scroll-snap-padding-top|scroll-snap-type|shape-image-threshold|shape-inside|shape-margin|shape-outside|size|speak|speak-as|speak-header|speak-numeral|speak-punctuation|speech-rate|stress|string-set|stroke|stroke-alignment|stroke-dashadjust|stroke-dasharray|stroke-dashcorner|stroke-dashoffset|stroke-linecap|stroke-linejoin|stroke-miterlimit|stroke-opacity|stroke-width|table-layout|tab-size|text-align|text-align-all|text-align-last|text-combine-upright|text-decoration|text-decoration-color|text-decoration-line|text-decoration-skip|text-decoration-style|text-emphasis|text-emphasis-color|text-emphasis-position|text-emphasis-style|text-indent|text-justify|text-orientation|text-overflow|text-shadow|text-space-collapse|text-space-trim|text-spacing|text-transform|text-underline-offset|text-underline-position|text-wrap|top|transform|transform-box|transform-origin|transform-style|transition|transition-delay|transition-duration|transition-property|transition-timing-function|unicode-bidi|user-select|vertical-align|visibility|voice-balance|voice-duration|voice-family|voice-pitch|voice-range|voice-rate|voice-stress|voice-volume|volume|white-space|widows|width|will-change|word-break|word-spacing|word-wrap|wrap-after|wrap-before|wrap-flow|wrap-inside|wrap-through|writing-mode|z-index):" # - default: # start: ":" # end: "[;^\\{]" # rules: [] - special: "!important" - identifier: ":active|:focus|:hover|:link|:visited|:link|:after|:before|$" - special: "(\\{|\\}|\\(|\\)|\\;|:|\\]|~|<|>|,)" # SCSS Varaibles - statement: "@import|@mixin|@extend" # Strings - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - special: "\"|'" # Comments & TODOs - comment: start: "\\/\\*" end: "\\*\\/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/csharp.yaml0000664000175000017510000000420415125206537021420 0ustar nileshnileshfiletype: csharp detect: filename: "\\.cs$" rules: # Class - identifier.class: "class +[A-Za-z0-9]+ *((:) +[A-Za-z0-9.]+)?" # Annotation - identifier.var: "@[A-Za-z]+" - preproc: "^[[:space:]]*#[[:space:]]*(define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)" - identifier: "([A-Za-z0-9_]*[[:space:]]*[()])" - type: "\\b(bool|byte|sbyte|char|decimal|double|float|IntPtr|int|uint|long|ulong|managed|unmanaged|nint|nuint|object|short|ushort|string|base|this|var|void)\\b" - statement: "\\b(alias|as|case|catch|checked|default|do|dynamic|else|finally|fixed|for|foreach|goto|if|is|lock|new|null|return|switch|throw|try|unchecked|when|while|with)\\b" - statement: "\\b(abstract|add|and|args|async|await|class|const|delegate|enum|event|explicit|extern|file|get|global|implicit|in|init|internal|interface|nameof|namespace|not|notnull|operator|or|out|override|params|partial|private|protected|public|readonly|record|ref|remove|required|scoped|sealed|set|sizeof|stackalloc|static|struct|typeof|unsafe|using|value|virtual|volatile|yield)\\b" # LINQ-only keywords (ones that cannot be used outside of a LINQ query - lots others can) - statement: "\\b(from|where|select|group|info|orderby|join|let|in|on|equals|by|ascending|descending)\\b" - special: "\\b(break|continue)\\b" - constant.bool: "\\b(true|false)\\b" - symbol.operator: "[\\-+/*=<>?:!~%&|]" - constant.number: "\\b([0-9._]+|0x[A-Fa-f0-9_]+|0b[0-1_]+)[FL]?\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([btnfr]|'|\\\"|\\\\)" - constant.specialChar: "\\\\u[A-Fa-f0-9]{4}" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\([btnfr]|'|\\\"|\\\\)" - constant.specialChar: "\\\\u[A-Fa-f0-9]{4}" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/crystal.yaml0000664000175000017510000000413015125206537021617 0ustar nileshnileshfiletype: crystal detect: filename: "\\.cr$" rules: # Asciibetical list of reserved words - statement: "\\b(abstract|alias|as|asm|begin|break|case|class|def|do|else|elsif|end|ensure|enum|extend|for|fun|if|in|include|instance_sizeof|lib|loop|macro|module|next|of|out|pointerof|private|protected|raise|require|rescue|return|select|self|sizeof|spawn|struct|super|then|type|typeof|uninitialized|union|unless|until|verbatim|when|while|with|yield)\\b" # Constants - constant: "\\b(true|false|nil)\\b" - constant.number: "\\b[0-9]+\\b" # Ones that can't be in the same regex because they include non-words. # The nil? one has to be after the constants. - statement: "\\b(nil\\?|as(\\?|\\b)|is_a\\?|responds_to\\?)" - type: "(\\$|@|@@)?\\b[A-Z]+[0-9A-Z_a-z]*" # Crystal "symbols" - constant: "([ ]|^):[0-9A-Z_]+\\b" # Some unique things we want to stand out - constant: "\\b(__FILE__|__LINE__)\\b" # Regular expressions - constant: "/([^/]|(\\\\/))*/[iomx]*|%r\\{([^}]|(\\\\}))*\\}[iomx]*" # Shell command expansion is in `backticks` or like %x{this}. These are # "double-quotish" (to use a perlism). - constant.string: "`[^`]*`|%x\\{[^}]*\\}" - constant.string: start: "`" end: "`" rules: [] - constant.string: start: "%x\\{" end: "\\}" rules: [] - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - symbol.brackets: start: "#\\{" end: "\\}" rules: - default: ".*" - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment.bright: start: "##" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - constant: start: "<<-?'?EOT'?" end: "^EOT" rules: [] zyedidia-micro-6a62575/runtime/syntax/crontab.yaml0000664000175000017510000000272115125206537021572 0ustar nileshnileshfiletype: crontab detect: filename: "crontab$|/tmp/crontab\\.\\w+$" header: "^#.*?/etc/crontab" rules: # The time and date fields are: # field allowed values # ----- -------------- # minute 0-59 # hour 0-23 # day of month 0-31 # month 0-12 (or names, see below) # day of week 0-7 (0 or 7 is Sun, or use names) - statement: "^([\\*0-9,\\-\\/]+)\\s+([\\*0-9,\\-\\/]+)\\s+([\\*0-9,\\-\\/]+)\\s+(([\\*0-9,\\-\\/]+)|(\\b(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\\b))\\s+(([\\*0-9,\\-\\/]+)|(\\b(sun|mon|tue|wed|thu|fri|sat)\\b))\\s+(.*)$\\n?" - constant: "^([\\*0-9,\\-\\/]+)\\s+([\\*0-9,\\-\\/]+)\\s+([\\*0-9,\\-\\/]+)\\s+(([\\*0-9,\\-\\/]+)|(\\b(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\\b))\\s+(([\\*0-9,\\-\\/]+)|(\\b(sun|mon|tue|wed|thu|fri|sat)\\b))" # Shell Values - type: "^[A-Z]+\\=" # Months and weekday keywords - constant: "\\b(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\\b" - constant: "\\b(sun|mon|tue|wed|thu|fri|sat)\\b" - type: "\\@(reboot|yearly|annually|monthly|weekly|daily|midnight|hourly)\\b" # Conditionals - special: "(\\{|\\}|\\(|\\)|\\;|\\]|\\[|`|\\\\|\\$|<|>|^|!|=|&|\\|)" - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/cpp.yaml0000664000175000017510000001407215125206537020726 0ustar nileshnileshfiletype: c++ detect: filename: "(\\.c(c|pp|xx)$|\\.h(h|pp|xx)?$|\\.ii?$|\\.(def)$)" signature: "\\b(namespace|class|public|protected|private|template|constexpr|noexcept|nullptr|throw)\\b" rules: - identifier: "\\b[A-Z_][0-9A-Z_]*\\b" - type: "\\b(auto|float|double|bool|char|int|short|long|enum|void|struct|union|typedef|(un)?signed|inline)\\b" - type: "\\b(((s?size)|((u_?)?int(8|16|32|64|ptr))|char(8|16|32))_t|wchar_t)\\b" - type: "\\b[a-z_][0-9a-z_]+(_t|_T)\\b" - type: "\\b(final|override)\\b" - statement: "\\b(volatile|const(expr|eval|init)?|mutable|register|thread_local|static|extern|decltype|explicit|virtual)\\b" - statement: "\\b(class|namespace|template|typename|this|friend|using|public|protected|private|noexcept)\\b" - statement: "\\b(concept|requires)\\b" - statement: "\\b(import|export|module)\\b" - statement: "\\b(for|if|while|do|else|case|default|switch)\\b" - statement: "\\b(try|throw|catch|operator|new|delete|static_assert)\\b" - statement: "\\b(goto|continue|break|return)\\b" - preproc: "^[[:space:]]*#[[:space:]]*(define|pragma|include|(un|ifn?)def|endif|el(if|se)|if|warning|error)|_Pragma" # Conditionally-supported/extension keywords - statement: "\\b(asm|fortran)\\b" # GCC builtins - statement: "(__attribute__[[:space:]]*\\(\\([^)]*\\)\\)|__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__)" # Operator Color - symbol.operator: "[-+*/%=<>.:;,~&|^!?]|\\b(sizeof|alignof|typeid|(and|or|xor|not)(_eq)?|bitor|compl|bitand|(const|dynamic|reinterpret|static)_cast)\\b" # Parenthetical Color - symbol.brackets: "[(){}]|\\[|\\]" # Integer Literals - constant.number: "(\\b([0-9]|0[0-7]|0[Xx][0-9A-Fa-f]|0[Bb][01])([Uu][Ll]?[Ll]?|[Ll][Ll]?[Uu]?)?\\b)" # Base case (Without ' separtor) - constant.number: "(\\b([1-9][0-9']*[0-9])([Uu][Ll]?[Ll]?|[Ll][Ll]?[Uu]?)?\\b)" # Decimal - constant.number: "(\\b(0[0-7][0-7']*[0-7])([Uu][Ll]?[Ll]?|[Ll][Ll]?[Uu]?)?\\b)" # Oct - constant.number: "(\\b(0[Xx][0-9A-Fa-f][0-9A-Fa-f']*[0-9A-Fa-f])([Uu][Ll]?[Ll]?|[Ll][Ll]?[Uu]?)?\\b)" # Hex - constant.number: "(\\b(0[Bb][01][01']*[01])([Uu][Ll]?[Ll]?|[Ll][Ll]?[Uu]?)?\\b)" # Binary # Decimal Floating-point Literals - constant.number: "(([0-9]?[.]?\\b[0-9]+)([Ee][+-]?[0-9]+)?[FfLl]?\\b)" # Base case optional interger part with exponent base case - constant.number: "(\\b([0-9]+[.][0-9]?)([Ee][+-]?[0-9]+)?[FfLl]?)" # Base case optional fractional part with exponent base case - constant.number: "(([0-9]?[.]?\\b[0-9]+)([Ee][+-]?[0-9][0-9']*[0-9])?[FfLl]?\\b)" # Base case optional interger part with exponent - constant.number: "(\\b([0-9]+[.][0-9]?)([Ee][+-]?[0-9][0-9']*[0-9])?[FfLl]?)" # Base case optional fractional part with exponent - constant.number: "(([0-9][0-9']*[0-9])?[.]?\\b([0-9][0-9']*[0-9])+([Ee][+-]?[0-9]+)?[FfLl]?\\b)" # Optional interger part with exponent base case - constant.number: "(\\b([0-9][0-9']*[0-9])+[.]([0-9][0-9']*[0-9])?([Ee][+-]?[0-9]+)?[FfLl]?)" # Optional fractional part with exponent base case - constant.number: "(([0-9][0-9']*[0-9])?[.]?\\b([0-9][0-9']*[0-9])+([Ee][+-]?[0-9][0-9']*[0-9])?[FfLl]?\\b)" # Optional interger part with exponent - constant.number: "(\\b([0-9][0-9']*[0-9])+[.]([0-9][0-9']*[0-9])?([Ee][+-]?[0-9][0-9']*[0-9])?[FfLl]?)" # Optional fractional part with exponent # Hexadecimal Floating-point Literals - constant.number: "(\\b0[Xx]([0-9a-zA-Z]?[.]?[0-9a-zA-Z]+)([Pp][+-]?[0-9]+)?[FfLl]?\\b)" # Base case optional interger part with exponent base case - constant.number: "(\\b0[Xx]([0-9a-zA-Z]+[.][0-9a-zA-Z]?)([Pp][+-]?[0-9]+)?[FfLl]?)" # Base case optional fractional part with exponent base case - constant.number: "(\\b0[Xx]([0-9a-zA-Z]?[.]?[0-9a-zA-Z]+)([Pp][+-]?[0-9][0-9']*[0-9])?[FfLl]?\\b)" # Base case optional interger part with exponent - constant.number: "(\\b0[Xx]([0-9a-zA-Z]+[.][0-9a-zA-Z]?)([Pp][+-]?[0-9][0-9']*[0-9])?[FfLl]?)" # Base case optional fractional part with exponent - constant.number: "(\\b0[Xx]([0-9a-zA-Z][0-9a-zA-Z']*[0-9a-zA-Z])?[.]?([0-9a-zA-Z][0-9a-zA-Z']*[0-9a-zA-Z])+([Pp][+-]?[0-9]+)?[FfLl]?\\b)" # Optional interger part with exponent base case - constant.number: "(\\b0[Xx]([0-9a-zA-Z][0-9a-zA-Z']*[0-9a-zA-Z])+[.]([0-9a-zA-Z][0-9a-zA-Z']*[0-9a-zA-Z])?([Pp][+-]?[0-9]+)?[FfLl]?)" # Optional fractional part with exponent base case - constant.number: "(\\b0[Xx]([0-9a-zA-Z][0-9a-zA-Z']*[0-9a-zA-Z])?[.]?([0-9a-zA-Z][0-9a-zA-Z']*[0-9a-zA-Z])+([Pp][+-]?[0-9][0-9']*[0-9])?[FfLl]?\\b)" # Optional interger part with exponent - constant.number: "(\\b0[Xx]([0-9a-zA-Z][0-9a-zA-Z']*[0-9a-zA-Z])+[.]([0-9a-zA-Z][0-9a-zA-Z']*[0-9a-zA-Z])?([Pp][+-]?[0-9][0-9']*[0-9])?[FfLl]?)" # Optional fractional part with exponent - constant.bool: "(\\b(true|false|NULL|nullptr|TRUE|FALSE)\\b)" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - constant.string: start: "'" end: "'" skip: "(\\\\.)|\\b([1-9][0-9']+[0-9]|0[0-7']+[0-7]|0[Xx][0-9A-Fa-f][0-9A-Fa-f']+[0-9A-Fa-f]|0[Bb][01][01']*[01])([Uu][Ll]?[Ll]?|[Ll][Ll]?[Uu]?)?\\b" rules: # TODO: Revert back to - error: "..+" once #3127 is merged - error: "[[:graph:]]{2,}'" - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/conky.yaml0000664000175000017510000001430715125206537021270 0ustar nileshnileshfiletype: conky detect: filename: "(\\.*conkyrc.*$|conky.conf)" rules: - type: "\\b(alignment|append_file|background|border_inner_margin|border_outer_margin|border_width|color0|color1|color2|color3|color4|color5|color6|color7|color8|color9|colorN|cpu_avg_samples|default_bar_height|default_bar_width|default_color|default_gauge_height|default_gauge_width|default_graph_height|default_graph_width|default_outline_color|default_shade_color|diskio_avg_samples|display|double_buffer|draw_borders|draw_graph_borders|draw_outline|draw_shades|extra_newline|font|format_human_readable|gap_x|gap_y|http_refresh|if_up_strictness|imap|imlib_cache_flush_interval|imlib_cache_size|lua_draw_hook_post|lua_draw_hook_pre|lua_load|lua_shutdown_hook|lua_startup_hook|mail_spool|max_port_monitor_connections|max_text_width|max_user_text|maximum_width|minimum_height|minimum_width|mpd_host|mpd_password|mpd_port|music_player_interval|mysql_host|mysql_port|mysql_user|mysql_password|mysql_db|net_avg_samples|no_buffers|nvidia_display|out_to_console|out_to_http|out_to_ncurses|out_to_stderr|out_to_x|override_utf8_locale|overwrite_file|own_window|own_window_class|own_window_colour|own_window_hints|own_window_title|own_window_transparent|own_window_type|pad_percents|pop3|sensor_device|short_units|show_graph_range|show_graph_scale|stippled_borders|temperature_unit|template|template0|template1|template2|template3|template4|template5|template6|template7|template8|template9|text|text_buffer_size|times_in_seconds|top_cpu_separate|top_name_width|total_run_times|update_interval|update_interval_on_battery|uppercase|use_spacer|use_xft|xftalpha|xftfont)\\b" # Configuration item constants - statement: "\\b(above|below|bottom_left|bottom_right|bottom_middle|desktop|dock|no|none|normal|override|skip_pager|skip_taskbar|sticky|top_left|top_right|top_middle|middle_left|middle_right|middle_middle|undecorated|yes)\\b" # Variables - preproc: "\\b(acpiacadapter|acpifan|acpitemp|addr|addrs|alignc|alignr|apcupsd|apcupsd_cable|apcupsd_charge|apcupsd_lastxfer|apcupsd_linev|apcupsd_load|apcupsd_loadbar|apcupsd_loadgauge|apcupsd_loadgraph|apcupsd_model|apcupsd_name|apcupsd_status|apcupsd_temp|apcupsd_timeleft|apcupsd_upsmode|apm_adapter|apm_battery_life|apm_battery_time|audacious_bar|audacious_bitrate|audacious_channels|audacious_filename|audacious_frequency|audacious_length|audacious_length_seconds|audacious_main_volume|audacious_playlist_length|audacious_playlist_position|audacious_position|audacious_position_seconds|audacious_status|audacious_title|battery|battery_bar|battery_percent|battery_short|battery_time|blink|bmpx_album|bmpx_artist|bmpx_bitrate|bmpx_title|bmpx_track|bmpx_uri|buffers|cached|cmdline_to_pid|color|color0|color1|color2|color3|color4|color5|color6|color7|color8|color9|combine|conky_build_arch|conky_build_date|conky_version|cpu|cpubar|cpugauge|cpugraph|curl|desktop|desktop_name|desktop_number|disk_protect|diskio|diskio_read|diskio_write|diskiograph|diskiograph_read|diskiograph_write|distribution|downspeed|downspeedf|downspeedgraph|draft_mails|else|endif|entropy_avail|entropy_bar|entropy_perc|entropy_poolsize|eval|eve|exec|execbar|execgauge|execgraph|execi|execibar|execigauge|execigraph|execp|execpi|flagged_mails|font|format_time|forwarded_mails|freq|freq_g|fs_bar|fs_bar_free|fs_free|fs_free_perc|fs_size|fs_type|fs_used|fs_used_perc|goto|gw_iface|gw_ip|hddtemp|head|hr|hwmon|i2c|i8k_ac_status|i8k_bios|i8k_buttons_status|i8k_cpu_temp|i8k_left_fan_rpm|i8k_left_fan_status|i8k_right_fan_rpm|i8k_right_fan_status|i8k_serial|i8k_version|ibm_brightness|ibm_fan|ibm_temps|ibm_volume|ical|iconv_start|iconv_stop|if_empty|if_existing|if_gw|if_match|if_mixer_mute|if_mounted|if_mpd_playing|if_running|if_smapi_bat_installed|if_up|if_updatenr|if_xmms2_connected|image|imap_messages|imap_unseen|ioscheduler|irc|kernel|laptop_mode|lines|loadavg|loadgraph|lua|lua_bar|lua_gauge|lua_graph|lua_parse|machine|mails|mboxscan|mem|memwithbuffers|membar|memwithbuffersbar|memeasyfree|memfree|memgauge|memgraph|memmax|memperc|mixer|mixerbar|mixerl|mixerlbar|mixerr|mixerrbar|moc_album|moc_artist|moc_bitrate|moc_curtime|moc_file|moc_rate|moc_song|moc_state|moc_timeleft|moc_title|moc_totaltime|monitor|monitor_number|mpd_album|mpd_artist|mpd_bar|mpd_bitrate|mpd_elapsed|mpd_file|mpd_length|mpd_name|mpd_percent|mpd_random|mpd_repeat|mpd_smart|mpd_status|mpd_title|mpd_track|mpd_vol|mysql|nameserver|new_mails|nodename|nodename_short|no_update|nvidia|obsd_product|obsd_sensors_fan|obsd_sensors_temp|obsd_sensors_volt|obsd_vendor|offset|outlinecolor|pb_battery|pid_chroot|pid_cmdline|pid_cwd|pid_environ|pid_environ_list|pid_exe|pid_nice|pid_openfiles|pid_parent|pid_priority|pid_state|pid_state_short|pid_stderr|pid_stdin|pid_stdout|pid_threads|pid_thread_list|pid_time_kernelmode|pid_time_usermode|pid_time|pid_uid|pid_euid|pid_suid|pid_fsuid|pid_gid|pid_egid|pid_sgid|pid_fsgid|pid_read|pid_vmpeak|pid_vmsize|pid_vmlck|pid_vmhwm|pid_vmrss|pid_vmdata|pid_vmstk|pid_vmexe|pid_vmlib|pid_vmpte|pid_write|platform|pop3_unseen|pop3_used|processes|read_tcp|read_udp|replied_mails|rss|running_processes|running_threads|scroll|seen_mails|shadecolor|smapi|smapi_bat_bar|smapi_bat_perc|smapi_bat_power|smapi_bat_temp|sony_fanspeed|stippled_hr|stock|swap|swapbar|swapfree|swapmax|swapperc|sysname|tab|tail|tcp_ping|tcp_portmon|template0|template1|template2|template3|template4|template5|template6|template7|template8|template9|texeci|texecpi|threads|time|to_bytes|top|top_io|top_mem|top_time|totaldown|totalup|trashed_mails|tztime|gid_name|uid_name|unflagged_mails|unforwarded_mails|unreplied_mails|unseen_mails|updates|upspeed|upspeedf|upspeedgraph|uptime|uptime_short|user_names|user_number|user_terms|user_times|user_time|utime|voffset|voltage_mv|voltage_v|weather|wireless_ap|wireless_bitrate|wireless_essid|wireless_link_bar|wireless_link_qual|wireless_link_qual_max|wireless_link_qual_perc|wireless_mode|words|xmms2_album|xmms2_artist|xmms2_bar|xmms2_bitrate|xmms2_comment|xmms2_date|xmms2_duration|xmms2_elapsed|xmms2_genre|xmms2_id|xmms2_percent|xmms2_playlist|xmms2_size|xmms2_smart|xmms2_status|xmms2_timesplayed|xmms2_title|xmms2_tracknr|xmms2_url)\\b" - identifier.var: "\\$\\{?[0-9A-Z_!@#$*?-]+\\}?" - symbol.operator: "(\\{|\\}|\\(|\\)|\\;|\\]|\\[|`|\\\\|\\$|<|>|!|=|&|\\|)" - constant.macro: "^TEXT$" zyedidia-micro-6a62575/runtime/syntax/colortest.yaml0000664000175000017510000000074315125206537022162 0ustar nileshnileshfiletype: colortest detect: filename: "ColorTest$" rules: - black: "\\bPLAIN\\b" - red: "\\bred\\b" - green: "\\bgreen\\b" - yellow: "\\byellow\\b" - blue: "\\bblue\\b" - magenta: "\\bmagenta\\b" - cyan: "\\bcyan\\b" - brightred: "\\bbrightred\\b" - brightgreen: "\\bbrightgreen\\b" - brightyellow: "\\bbrightyellow\\b" - brightblue: "\\bbrightblue\\b" - brightmagenta: "\\bbrightmagenta\\b" - brightcyan: "\\bbrightcyan\\b" zyedidia-micro-6a62575/runtime/syntax/coffeescript.yaml0000664000175000017510000000374215125206537022622 0ustar nileshnileshfiletype: coffeescript detect: filename: "\\.coffee$" rules: - symbol.operator: "([-+/*=<>!~%?:&|]|[.]{3})|\\b(and|or|is|isnt|not)\\b" - identifier.class: "([A-Za-z_][A-Za-z0-9_]*:[[:space:]]*(->|\\()|->)" - symbol.brackets: "[()]" - statement: "\\b(await|when|catch|continue|debugger|default|by|until)\\b" - statement: "\\b(delete|do|else|export|finally|for|class|extends|while|then)\\b" - statement: "\\b(get|if|import|from|in|instanceof|new|reject|resolve|return)\\b" - statement: "\\b(set|super|switch|this|throw|try|typeof|with|yield|unless)\\b" - constant.bool: "\\b(true|false|yes|no|on|off)\\b" - constant.bool.false: "\\b(false|no|off)\\b" - constant.bool.true: "\\b(true|yes|on)\\b" - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b" - constant.number: "\\b[-+]?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?" - constant.number: "\\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?" - identifier: "@[A-Za-z0-9_]*" - error: "\\b(enum|implements|interface|package|private|protected|public)" - constant: "\\b(globalThis|Infinity|null|undefined|NaN)\\b" - constant: "\\b(null|undefined|NaN)\\b" - constant: "\\b(true|false|yes|no|on|off)\\b" - type: "\\b(Array|Boolean|Date|Enumerator|Error|Function|Generator|Map|Math)\\b" - type: "\\b(Number|Object|Promise|Proxy|Reflect|RegExp|Set|String|Symbol|WeakMap|WeakSet)\\b" - type: "\\b(BigInt64Array|BigUint64Array|Float32Array|Float64Array|Int16Array)\\b" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "###" end: "###" rules: [] - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/cmake.yaml0000664000175000017510000000223515125206537021222 0ustar nileshnileshfiletype: cmake detect: filename: "(CMakeLists\\.txt|\\.cmake)$" rules: - identifier.var: "^[[:space:]]*[A-Z0-9_]+" - preproc: "^[[:space:]]*(include|include_directories|include_external_msproject)\\b" - statement: "^[[:space:]]*\\b((else|end)?if|else|(end)?while|(end)?foreach|break)\\b" - statement: "\\b(COPY|NOT|COMMAND|PROPERTY|POLICY|TARGET|EXISTS|IS_(DIRECTORY|ABSOLUTE)|DEFINED)\\b[[:space:]]" - statement: "[[:space:]]\\b(OR|AND|IS_NEWER_THAN|MATCHES|(STR|VERSION_)?(LESS|GREATER|EQUAL))\\b[[:space:]]" - special: "^[[:space:]]*\\b((end)?(function|macro)|return)" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - preproc: start: "\\$(\\{|ENV\\{)" end: "\\}" rules: [] - identifier.macro: "\\b(APPLE|UNIX|WIN32|CYGWIN|BORLAND|MINGW|MSVC(_IDE|60|71|80|90)?)\\b" - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/clojure.yaml0000664000175000017510000000172715125206537021612 0ustar nileshnileshfiletype: clojure detect: filename: "\\.(clj[sc]?|edn)$" rules: # Constants - constant.bool: "\\b(true|false)\\b" - constant.macro: "\\b(nil)\\b" # Valid numbers - constant.number: "[\\-]?[0-9]+?\\b" - constant.number: "0x[0-9][A-Fa-f]+?\\b" - constant.number: "[\\-]?(3[0-6]|2[0-9]|1[0-9]|[2-9])r[0-9A-Z]+?\\b" # Invalid numbers - error: "[\\-]?([4-9][0-9]|3[7-9]|1|0)r[0-9A-Z]+?\\b" # Symbols - symbol.operator: "[=>+\\-*/'?]" # Types/casting - type: "\\b(byte|short|(big)?int(eger)?|long|float|num|bigdec|rationalize)\\b" # String highlighting - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "(\\\\u[0-9A-fa-f]{4,4}|\\\\newline|\\\\space|\\\\tab|\\\\formfeed|\\\\backspace|\\\\return|\\\\.)" # Comments - comment: start: ";" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/cake.yaml0000664000175000017510000000023615125206537021044 0ustar nileshnileshfiletype: cake detect: filename: "\\.cake$" rules: - include: "csharp" - preproc: "^[[:space:]]*#(addin|break|l(oad)?|module|r(eference)?|tool)" zyedidia-micro-6a62575/runtime/syntax/caddyfile.yaml0000664000175000017510000000072615125206537022071 0ustar nileshnileshfiletype: caddyfile detect: filename: "Caddyfile" rules: - identifier: "^\\s*\\S+(\\s|$)" - type: "^([\\w.:/-]+,? ?)+[,{]$" - constant.specialChar: "\\s{$" - constant.specialChar: "^\\s*}$" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - preproc: "\\{(\\w+|\\$\\w+|%\\w+%)\\}" - comment: start: "#" end: "$" rules: [] zyedidia-micro-6a62575/runtime/syntax/c.yaml0000664000175000017510000000550015125206537020362 0ustar nileshnileshfiletype: c detect: filename: "(\\.(c|C)$|\\.(h|H)$|\\.ii?$|\\.(def)$)" rules: - identifier: "\\b[A-Z_][0-9A-Z_]+\\b" - type: "\\b(_Atomic|_BitInt|float|double|_Decimal32|_Decimal64|_Decimal128|_Complex|complex|_Imaginary|imaginary|_Bool|bool|char|int|short|long|enum|void|struct|union|typedef|typeof|typeof_unqual|(un)?signed|inline|_Noreturn)\\b" - type: "\\b((s?size)|((u_?)?int(8|16|32|64|ptr))|char(8|16|32)|wchar)_t\\b" # GCC float/decimal/fixed types - type: "\\b(_Float16|__fp16|_Float32|_Float32x|_Float64|_Float64x|__float80|_Float128|_Float128x|__float128|__ibm128|__int128|_Fract|_Sat|_Accum)\\b" - type: "\\b[a-z_][0-9a-z_]+(_t|_T)\\b" - statement: "\\b(auto|volatile|register|restrict|_Alignas|alignas|_Alignof|alignof|static|const|constexpr|extern|_Thread_local|thread_local)\\b" - statement: "\\b(for|if|while|do|else|case|default|switch|_Generic|_Static_assert|static_assert)\\b" - statement: "\\b(goto|continue|break|return)\\b" - statement: "\\b(asm|fortran)\\b" - preproc: "^[[:space:]]*#[[:space:]]*(define|embed|pragma|include|(un|ifn?)def|endif|el(if|ifdef|ifndef|se)|if|line|warning|error|__has_include|__has_embed|__has_c_attribute)" - preproc: "^[[:space:]]*_Pragma\\b" # GCC builtins - statement: "__attribute__[[:space:]]*\\(\\([^)]*\\)\\)" - statement: "__(aligned|asm|builtin|extension|hidden|inline|packed|restrict|section|typeof|weak)__" # Operator Color - symbol.operator: "[-+*/%=<>.:;,~&|^!?]|\\b(offsetof|sizeof)\\b" - symbol.brackets: "[(){}]|\\[|\\]" # Integer Constants - constant.number: "(\\b([1-9][0-9]*|0[0-7]*|0[Xx][0-9A-Fa-f]+|0[Bb][01]+)([Uu][Ll]?[Ll]?|[Ll][Ll]?[Uu]?)?\\b)" # Decimal Floating Constants - constant.number: "(\\b(([0-9]*[.][0-9]+|[0-9]+[.][0-9]*)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)[FfLl]?\\b)" # Hexadecimal Floating Constants - constant.number: "(\\b0[Xx]([0-9A-Za-z]*[.][0-9A-Za-z]+|[0-9A-Za-z]+[.][0-9A-Za-z]*)[Pp][+-]?[0-9]+[FfLl]?\\b)" - constant.bool: "(\\b(true|false|NULL|nullptr|TRUE|FALSE)\\b)" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - constant.string: start: "'" end: "'" skip: "\\\\." rules: # TODO: Revert back to - error: "..+" once #3127 is merged - error: "[[:graph:]]{2,}'" - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/bat.yaml0000664000175000017510000001005515125206537020707 0ustar nileshnileshfiletype: batch detect: filename: "(\\.bat$|\\.cmd$)" rules: # Numbers - constant.number: "\\b[0-9]+\\b" # Brackets and symbols - special: "(\\{|\\}|\\(|\\)|\\;|\\]|\\[|`|\\\\|\\$|<|>|!|=|&|\\|)" # Conditionals and control flow # note (?i) means case insensitive match - type: "\\b(?i)(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|then|until|while)\\b" - type: "\\b(?i)(equ|neq|lss|leq|gtr|geq|on|off)\\b" - type: "\\b(?i)(goto|for|in|do|call|exit|not|exist|errorlevel|defined)\\b" - type: "\\b(?i)(prn|nul|lpt3|lpt2|lpt1|con|com4|com3|com2|com1|aux)\\b" # keywords - statement: "\\b(?i)(adprep|append|arp|assoc|at|atmadm|attrib|auditpol|autochk|autoconv|autofmt|bcdboot|bcdedit|bdehdcfg|bitsadmin|bootcfg|break|brea)\\b" - statement: "\\b(?i)(cacls|cd|certreq|certutil|chcp|change|choice|cipher|chdir|chkdsk|chkntfs|chglogon|chgport|chgusr|clip|cls|clscluadmin|cluster|cmd|cmdkey|cmstp|color)\\b" - statement: "\\b(?i)(comp|compact|convert|copy|cprofile|cscript|csvde|date|dcdiag|dcgpofix|dcpromo|defra|del|dfscmd|dfsdiag|dfsrmig|diantz|dir|dirquota|diskcomp|diskcopy|diskpart|diskperf|diskraid|diskshadow|dispdiag|doin|dnscmd|doskey|driverquery|dsacls|dsadd|dsamain|dsdbutil|dsget|dsmgmt|dsmod|dsmove|dsquery|dsrm)\\b" - statement: "\\b(?i)(echo|edit|endlocal|erase|esentutl|eventcreate|eventquery|eventtriggers|evntcmd|expand|extract)\\b" - statement: "\\b(?i)(fc|filescrn|find|findstr|finger|flattemp|fonde|forfiles|format|freedisk|fs|fsutil|ftp|ftype|fveupdate|getmac|gettype|gpfixup|gpresult|gpupdate|graftabl)\\b" - statement: "\\b(?i)(hashgen|hep|help|helpctr|hostname|icacls|iisreset|inuse|ipconfig|ipxroute|irftp|ismserv|jetpack|keyb|klist|ksetup|ktmutil|ktpass|label|ldifd|ldp|lodctr|logman|logoff|lpq|lpr|macfile)\\b" - statement: "\\b(?i)(makecab|manage-bde|mapadmin|md|mkdir|mklink|mmc|mode|more|mount|mountvol|move|mqbup|mqsvc|mqtgsvc|msdt|msg|msiexec|msinfo32|mstsc|nbtstat|net computer|net group)\\b" - statement: "\\b(?i)(net localgroup|net print|net session|net share|net start|net stop|net use|net user|net view|net|netcfg|netdiag|netdom|netsh|netstat|nfsadmin|nfsshare|nfsstat|nlb)\\b" - statement: "\\b(?i)(nlbmgr|nltest|nslookup|ntackup|ntcmdprompt|ntdsutil|ntfrsutl|openfiles|pagefileconfig|path|pathping|pause|pbadmin|pentnt|perfmon|ping|pnpunatten|pnputil|popd)\\b" - statement: "\\b(?i)(powercfg|powershell|powershell_ise|print|prncnfg|prndrvr|prnjobs|prnmngr|prnport|prnqctl|prompt|pubprn|pushd|pushprinterconnections|pwlauncher|qappsrv|qprocess)\\b" - statement: "\\b(?i)(query|quser|qwinsta|rasdial|rcp|rd|rdpsign|regentc|recover|redircmp|redirusr|reg|regini|regsvr32|relog|ren|rename|rendom|repadmin|repair-bde|replace|reset|restore)\\b" - statement: "\\b(?i)(rxec|risetup|rmdir|robocopy|route|rpcinfo|rpcping|rsh|runas|rundll32|rwinsta|scp|sc|setlocal|session|schtasks|scwcmd|secedit|serverceipoptin|servrmanagercmd|serverweroptin|set|setspn)\\b" - statement: "\\b(?i)(setx|sfc|shadow|shift|showmount|shutdown|sort|ssh|start|storrept|subst|sxstrace|ysocmgr|systeminfo|takeown|tapicfg|taskkill|tasklist|tcmsetup|telnet|tftp|time)\\b" - statement: "\\b(?i)(timeout|title|tlntadmn|tpmvscmgr|tpmvscmgr|tacerpt|tracert|tree|tscon|tsdiscon|tsecimp|tskill|tsprof|type|typeperf|tzutil|uddiconfig|umount|unlodctr|ver|verify)\\b" - statement: "\\b(?i)(verifier|verif|vol|vssadmin|w32tm|waitfor|wbadmin|wdsutil|wecutil|wevtutil|where|whoami|winnt|winnt32|winpop|winrm|winrs|winsat|wlbs|mic|wscript|xcopy)\\b" # / Flags - constant: "(/\\w+)" # Variables - special: "(%%\\w+)" - special: "(%\\w+%)" # Conditional flags - type: "--[a-z-]+" - type: "\\ -[a-z]+" - identifier: "\\$\\{?[0-9A-Z_!@#$*?-]+\\}?" - identifier: "\\$\\{?[0-9A-Z_!@#$*?-]+\\}?" # "" String - constant.string: start: \" end: \" skip: \. rules: - constant.specialChar: (\\0|\\\\|\\t|\\n|\\r|\\"|\\') - constant.unicode: \\u\{[[:xdigit:]]+} # '' string - constant.string: "(\\'.+\\')" # rem as comment - comment.rem: "(?i)(rem\\s.*)" # :: as comment - comment.rem: "(?i)(\\:\\:\\s.*)" zyedidia-micro-6a62575/runtime/syntax/awk.yaml0000664000175000017510000000273315125206537020727 0ustar nileshnileshfiletype: awk detect: filename: "\\.awk$" header: "^#!.*bin/(env +)?awk( |$)" rules: - preproc: "\\$[A-Za-z0-9_!@#$*?\\-]+" - preproc: "\\b(ARGC|ARGIND|ARGV|BINMODE|CONVFMT|ENVIRON|ERRNO|FIELDWIDTHS)\\b" - preproc: "\\b(FILENAME|FNR|FS|IGNORECASE|LINT|NF|NR|OFMT|OFS|ORS)\\b" - preproc: "\\b(PROCINFO|RS|RT|RSTART|RLENGTH|SUBSEP|TEXTDOMAIN)\\b" - identifier.class: "\\b(function|extension|BEGIN|END)\\b" - symbol.operator: "[\\-+*/%^|!=&<>?;:]|\\\\|\\[|\\]" - statement: "\\b(for|if|while|do|else|in|delete|exit)\\b" - special: "\\b(break|continue|return)\\b" - statement: "\\b(close|getline|next|nextfile|print|printf|system|fflush)\\b" - statement: "\\b(atan2|cos|exp|int|log|rand|sin|sqrt|srand)\\b" - statement: "\\b(asort|asorti|gensub|gsub|index|length|match)\\b" - statement: "\\b(split|sprintf|strtonum|sub|substr|tolower|toupper)\\b" - statement: "\\b(mktime|strftime|systime)\\b" - statement: "\\b(and|compl|lshift|or|rshift|xor)\\b" - statement: "\\b(bindtextdomain|dcgettext|dcngettext)\\b" - special: "/.*[^\\\\]/" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/ats.yaml0000664000175000017510000000775315125206537020743 0ustar nileshnileshfiletype: ATS detect: filename: "\\.(d|h|s)ats$" rules: - default: \b[[:alnum:]]+[^0-9A-Za-z] # Operators - symbol.operator: "[.:;+`|~<>?='\\&]|/|%|-|,|!|\\*|@|\\#" - symbol.operator: \^ # Types, abstract types and some predefined sorts - type: \b(addr|age?z|bool|char|cls|schar|uchar|double|ldouble|eff|exn|float|int(ptr)?|lincloptr|uint)\b - type: \b(lint|ulint|llint|ullint|nat|ptr|real|ref|size_t|ssize_t|sint|usint|string|tkind|viewt|v?t0p|vt|void)\b - type: \b(prop|t[@0]ype|type|viewt[@0]ype|viewtype|vt[@0]ype|vtype|view)\b - type: \b(prop[+-]|t[@0]ype[+-]|type[+-]|viewt[@0]ype[+-]|viewtype[+-]|vt[@0]ype[+-]|vtype[+-]|view[+-]) # Statements - statement: \b(abstype|abst|absprop|absviewt|absvt(ype)?|absview|and|andalso|as|(re)?assume|begin|(pr)?case|s?case)\b - statement: \b(classdec|dataprop|data(v|view)?type|dataview|datasort|do|dynload|else|end|exception|extype|extva(r|l)|s?if)\b - statement: \b(ifcase|import|for|in|infix(l|r)?|let|local|macrodef|macdef|not|of|op|or|orelse|overload|(pre|post|non)fix)\b - statement: \b(propdef|rec|sortdef|stacst|stadef|staload|stavar|sta(tic)?|symelim|symintr|tkindef|then|try|viewdef|v?typedef)\b - statement: \b(viewtypedef|(pr)?va(l|r)|when|where|while|with|withtype|withprop|withv(iew)?type|withview)\b - statement: \b(abst[@0]ype|absviewt[@0]?ype|absvt[@0]ype|abstbox|abstflat|absvtbox|absvtflat|absimpl|absreimpl|abs)\b - statement: \b(case[+-]|(pr)?va(l|r)[+-]|for\*|while\*) # Numbers - constant.number: \b[0-9.]+([eE][+-]?[0-9]+)?[fFlL]?\b - constant.number: \b0[xX][0-9A-Fa-f]*(\.[0-9A-Fa-f]*)?[pP][+-]?[0-9]+[fFlL]?\b - constant.number: \b([0-9]+|0[xX][0-9A-Fa-f]+)[lLuU]*\b # Function-related keywords, special functions and namespaces. Not really identifiers - identifier: \b(fix|(pr)?fu?n|fnx|castfn|praxi|extern|lam|llam|(pr)?implement|(pr)?implmnt)\b - identifier: \b(fix@|fold@|free@|lam@|llam@|addr@|view@|ref@|fn\*) - identifier: \$\w*\b # Other keywords, function effects... - special: (\$(arrpsz|arrptrsize|break|continue|d2ctype|delay|effmask_(ntm|exn|ref|wrt|all)))\b - special: (\$(effmask|extern|extype_struct|extype|extkind|extval|extfcall|extmcall|ldelay|literal))\b - special: (\$(li?st_vt|li?st_t|li?st|myfilename|myfunction|mylocation|raise|rec(ord)?_vt))\b - special: (\$(rec(ord)?_t|rec(ord)?|showtype|solver_assert|solver_verify|tempenver))\b - special: (\$(tup(le)?_vt|tup(le)?_t|tup(le)?|tyrep|vararg|vcopyenv_vt|vcopyenv_v))\b - special: \!(wrt|exnref|exnwrt|exn|refwrt|ref|all|ntm|laz)\b - special: \b(fun(0|1)|(lin)?cloptr(0|1)?|cloref(0|1)?|clo(0|1)?|lin|prf)\b - special: \b(f?print(ln)?!|prerr(ln)?!|tupz!) # Some C macros and other ATS macros - preproc: ^[[:space:]]*#[[:space:]]*(define|pragma|include|(un|ifn?)def|endif|el(if|se)|if|warning|error|assert)\b - preproc: ^[[:space:]]*#[[:space:]]*(codegen2|codegen3|elifdef|elifndef|prerr|print|require|then|staload|dynload)\b # Boolean values - constant.bool: \b(true|false|null)\b # The "%{ ... %}" block inserts foreign code into ATS at compile-time # Code inside of it is generally C or JavaScript - default: start: "%{[#^$]?" end: "%}" skip: "\\." limit-group: symbol.operator rules: - include: "c" - include: "javascript" # Strings and chars - constant.string: \"[^"]*\" - constant.string: \'[^']*\' # Comments # "////" comments everything until it reaches EOF - comment.block: start: //// end: $a rules: - todo: (TODO|XXX|FIXME) - comment.line: start: // end: $ rules: - todo: (TODO|XXX|FIXME) # ML-like block comment - comment.block: start: \(\* end: \*\) rules: - todo: (TODO|XXX|FIXME) # C-like block comment - comment.block: start: /\* end: \*\/ rules: - todo: (TODO|XXX|FIXME) zyedidia-micro-6a62575/runtime/syntax/asm.yaml0000664000175000017510000002323715125206537020727 0ustar nileshnileshfiletype: asm detect: filename: "\\.(S|s|asm)$" rules: # This file is made mainly for NASM assembly ## Instructions # x86 - statement: "\\b(?i)(mov|aaa|aad|aam|aas|adc|add|and|call|cbw|clc|cld|cli|cmc|cmp|cmpsb|cmpsw|cwd|daa|das|dec|div|esc|hlt|idiv|imul|in|inc|int|into|iret|ja|jae|jb|jbe|jc|je|jg|jge|jl|jle|jna|jnae|jnb|jnbe|jnc|jne|jng|jnge|jnl|jnle|jno|jnp|jns|jnz|jo|jp|jpe|jpo|js|jz|jcxz|jmp|lahf|lds|lea|les|lock|lodsb|lodsw|loop|loope|loopne|loopnz|loopz|movsb|movsw|mul|neg|nop|or|pop|popf|push|pushf|rcl|rcr|rep|repe|repne|repnz|repz|ret|retn|retf|rol|ror|sahf|sal|sar|sbb|scasb|scasw|shl|shr|stc|std|sti|stosb|stosw|sub|test|wait|xchg|xlat|xor)(?-i)\\b" - statement: "\\b(?i)(bound|enter|ins|leave|outs|popa|pusha)(?-i)\\b" - statement: "\\b(?i)(arpl|clts|lar|lgdt|lidt|lldt|lmsw|loadall|lsl|ltr|sgdt|sidt|sldt|smsw|str|verr|verw)(?-i)\\b" - statement: "\\b(?i)(bsf|bsr|bt|btc|btr|bts|cdq|cmpsd|cwde|insd|iret|iretd|iretf|jecxz|lfs|lgs|lss|lodsd|loopw|loopew|loopnew|loopnzw|loopzw|loopd|looped|loopned|loopnzd|loopzd|cr|tr|dr|movsd|movsx|movzx|outsd|popad|popfd|pushad|pushfd|scasd|seta|setae|setb|setbe|setc|sete|setg|setge|setl|setle|setna|setnae|setnb|setnbe|setnc|setne|setng|setnge|setnl|setnle|setno|setnp|setns|setnz|seto|setp|setpe|setpo|sets|setz|shdl|shrd|stosd)(?-i)\\b" - statement: "\\b(?i)(bswap|cmpxcgh|invd|invlpg|wbinvd|xadd)(?-i)\\b" - statement: "\\b(?i)(cpuid|cmpxchg8b|rdmsr|rdtsc|wrmsr|rsm)(?-i)\\b" - statement: "\\b(?i)(rdpmc)(?-i)\\b" - statement: "\\b(?i)(syscall|sysret)(?-i)\\b" - statement: "\\b(?i)(cmova|cmovae|cmovb|cmovbe|cmovc|cmove|cmovg|cmovge|cmovl|cmovle|cmovna|cmovnae|cmovnb|cmovnbe|cmovnc|cmovne|cmovng|cmovnge|cmovnle|cmovno|cmovpn|cmovns|cmovnz|cmovo|cmovp|cmovpe|cmovpo|cmovs|cmovz|sysenter|sysexit|ud2)(?-i)\\b" - statement: "\\b(?i)(maskmovq|movntps|movntq|prefetch0|prefetch1|prefetch2|prefetchnta|sfence)(?-i)\\b" - statement: "\\b(?i)(clflush|lfence|maskmovdqu|mfence|movntdq|movnti|movntpd|pause)(?-i)\\b" - statement: "\\b(?i)(monitor|mwait)(?-i)\\b" - statement: "\\b(?i)(cdqe|cqo|cmpsq|cmpxchg16b|iretq|jrcxz|lodsq|movsdx|popfq|pushfq|rdtscp|scasq|stosq|swapgs)(?-i)\\b" - statement: "\\b(?i)(clgi|invlpga|skinit|stgi|vmload|vmmcall|vmrun|vmsave)(?-i)\\b" - statement: "\\b(?i)(vmptrdl|vmptrst|vmclear|vmread|vmwrite|vmcall|vmlaunch|vmresume|vmxoff|vmxon)(?-i)\\b" - statement: "\\b(?i)(lzcnt|popcnt)(?-i)\\b" - statement: "\\b(?i)(bextr|blcfill|blci|blcic|blcmask|blcs|blsfill|blsic|t1mskc|tzmsk)(?-i)\\b" # x87 - statement: "\\b(?i)(f2xm1|fabs|fadd|faddp|fbld|fbstp|fchs|fclex|fcom|fcomp|fcompp|fdecstp|fdisi|fdiv|fvidp|fdivr|fdivrp|feni|ffree|fiadd|ficom|ficomp|fidiv|fidivr|fild|fimul|fincstp|finit|fist|fistp|fisub|fisubr|fld|fld1|fldcw|fldenv|fldenvw|fldl2e|fldl2t|fldlg2|fldln2|fldpi|fldz|fmul|fmulp|fnclex|fndisi|fneni|fninit|fnop|fnsave|fnsavenew|fnstcw|fnstenv|fnstenvw|fnstsw|fpatan|fprem|fptan|frndint|frstor|frstorw|fsave|fsavew|fscale|fsqrt|fst|fstcw|fstenv|fstenvw|fstp|fstpsw|fsub|fsubp|fsubr|fsubrp|ftst|fwait|fxam|fxch|fxtract|fyl2x|fyl2xp1)(?-i)\\b" - statement: "\\b(?i)(fsetpm)(?-i)\\b" - statement: "\\b(?i)(fcos|fldenvd|fsaved|fstenvd|fprem1|frstord|fsin|fsincos|fstenvd|fucom|fucomp|fucompp)(?-i)\\b" - statement: "\\b(?i)(fcmovb|fcmovbe|fcmove|fcmove|fcmovnb|fcmovnbe|fcmovne|fcmovnu|fcmovu)(?-i)\\b" - statement: "\\b(?i)(fcomi|fcomip|fucomi|fucomip)(?-i)\\b" - statement: "\\b(?i)(fxrstor|fxsave)(?-i)\\b" - statement: "\\b(?i)(fisttp)(?-i)\\b" - statement: "\\b(?i)(ffreep)(?-i)\\b" # SIMD - statement: "\\b(?i)(emms|movd|movq|packssdw|packsswb|packuswb|paddb|paddw|paddd|paddsb|paddsw|paddusb|paddusw|pand|pandn|por|pxor|pcmpeqb|pcmpeqw|pcmpeqd|pcmpgtb|pcmpgtw|pcmpgtd|pmaddwd|pmulhw|pmullw|psllw|pslld|psllq|psrad|psraw|psrlw|psrld|psrlq|psubb|psubw|psubd|psubsb|psubsw|psubusb|punpckhbw|punpckhwd|punpckhdq|punkcklbw|punpckldq|punpcklwd)(?-i)\\b" - statement: "\\b(?i)(paveb|paddsiw|pmagw|pdistib|psubsiw|pmwzb|pmulhrw|pmvnzb|pmvlzb|pmvgezb|pmulhriw|pmachriw)(?-i)\\b" - statement: "\\b(?i)(femms|pavgusb|pf2id|pfacc|pfadd|pfcmpeq|pfcmpge|pfcmpgt|pfmax|pfmin|pfmul|pfrcp|pfrcpit1|pfrcpit2|pfrsqit1|pfrsqrt|pfsub|pfsubr|pi2fd|pmulhrw|prefetch|prefetchw)(?-i)\\b" - statement: "\\b(?i)(pf2iw|pfnacc|pfpnacc|pi2fw|pswapd)(?-i)\\b" - statement: "\\b(?i)(pfrsqrtv|pfrcpv)(?-i)\\b" - statement: "\\b(?i)(addps|addss|cmpps|cmpss|comiss|cvtpi2ps|cvtps2pi|cvtsi2ss|cvtss2si|cvttps2pi|cvttss2si|divps|divss|ldmxcsr|maxps|maxss|minps|minss|movaps|movhlps|movhps|movlhps|movlps|movmskps|movntps|movss|movups|mulps|mulss|rcpps|rcpss|rsqrtps|rsqrtss|shufps|sqrtps|sqrtss|stmxcsr|subps|subss|ucomiss|unpckhps|unpcklps)(?-i)\\b" - statement: "\\b(?i)(andnps|andps|orps|pavgb|pavgw|pextrw|pinsrw|pmaxsw|pmaxub|pminsw|pminub|pmovmskb|pmulhuw|psadbw|pshufw|xorps)(?-i)\\b" - statement: "\\b(?i)(movups|movss|movlps|movhlps|movlps|unpcklps|unpckhps|movhps|movlhps|prefetchnta|prefetch0|prefetch1|prefetch2|nop|movaps|cvtpi2ps|cvtsi2ss|cvtps2pi|cvttss2si|cvtps2pi|cvtss2si|ucomiss|comiss|sqrtps|sqrtss|rsqrtps|rsqrtss|rcpps|andps|orps|xorps|addps|addss|mulps|mulss|subps|subss|minps|minss|divps|divss|maxps|maxss|pshufw|ldmxcsr|stmxcsr|sfence|cmpps|cmpss|pinsrw|pextrw|shufps|pmovmskb|pminub|pmaxub|pavgb|pavgw|pmulhuw|movntq|pminsw|pmaxsw|psadbw|maskmovq)(?-i)\\b" - statement: "\\b(?i)(addpd|addsd|addnpd|cmppd|cmpsd)(?-i)\\b" - statement: "\\b(?i)(addpd|addsd|andnpd|andpd|cmppd|cmpsd|comisd|cvtdq2pd|cvtdq2ps|cvtpd2dq|cvtpd2pi|cvtpd2ps|cvtpi2pd|cvtps2dq|cvtps2pd|cvtsd2si|cvtsd2ss|cvtsi2sd|cvtss2sd|cvttpd2dq|cvttpd2pi|cvttps2dq|cvttsd2si|divpd|divsd|maxpd|maxsd|minpd|minsd|movapd|movhpd|movlpd|movmskpd|movsd|movupd|mulpd|mulsd|orpd|shufpd|sqrtpd|sqrtsd|subpd|subsd|ucomisd|unpckhpd|unpcklpd|xorpd)(?-i)\\b" - statement: "\\b(?i)(movdq2q|movdqa|movdqu|movq2dq|paddq|psubq|pmuludq|pshufhw|pshuflw|pshufd|pslldq|psrldq|punpckhqdq|punpcklqdq)(?-i)\\b" - statement: "\\b(?i)(addsubpd|addsubps|haddpd|haddps|hsubpd|hsubps|movddup|movshdup|movsldu)(?-i)\\b" - statement: "\\b(?i)(lddqu)(?-i)\\b" - statement: "\\b(?i)(psignw|psignd|psignb|pshufb|pmulhrsw|pmaddubsw|phsubw|phsubsw|phsubd|phaddw|phaddsw|phaddd|palignr|pabsw|pabsd|pabsb)(?-i)\\b" - statement: "\\b(?i)(dpps|dppd|blendps|blendpd|blendvps|blendvpd|roundps|roundss|roundpd|roundsd|insertps|extractps)(?-i)\\b" - statement: "\\b(?i)(mpsadbw|phminposuw|pmulld|pmuldq|pblendvb|pblendw|pminsb|pmaxsb|pminuw|pmaxuw|pminud|pmaxud|pminsd|pmaxsd|pinsrb|pinsrd/pinsrq|pextrb|pextrw|pextrd/pextrq|pmovsxbw|pmovzxbw|pmovsxbd|pmovzxbd|pmovsxbq|pmovzxbq|pmovsxwd|pmovzxwd|pmovsxwq|pmovzxwq|pmovsxdq|pmovzxdq|ptest|pcmpeqq|packusdw|movntdqa)(?-i)\\b" - statement: "\\b(?i)(extrq|insertq|movntsd|movntss)(?-i)\\b" - statement: "\\b(?i)(crc32|pcmpestri|pcmpestrm|pcmpistri|pcmpistrm|pcmpgtq)(?-i)\\b" - statement: "\\b(?i)(vfmaddpd|vfmaddps|vfmaddsd|vfmaddss|vfmaddsubpd|vfmaddsubps|vfmsubaddpd|vfmsubaddps|vfmsubpd|vfmsubps|vfmsubsd|vfmsubss|vfnmaddpd|vfnmaddps|vfnmaddsd|vfnmaddss|vfnmsubps|vfnmsubsd|vfnmsubss)(?-i)\\b" # Crypto - statement: "\\b(?i)(aesenc|aesenclast|aesdec|aesdeclast|aeskeygenassist|aesimc)(?-i)\\b" - statement: "\\b(?i)(sha1rnds4|sha1nexte|sha1msg1|sha1msg2|sha256rnds2|sha256msg1|sha256msg2)(?-i)\\b" # Undocumented - statement: "\\b(?i)(aam|aad|salc|icebp|loadall|loadalld|ud1)(?-i)\\b" ## Registers - identifier: "\\b(?i)(al|ah|bl|bh|cl|ch|dl|dh|bpl|sil|r8b|r9b|r10b|r11b|dil|spl|r12b|r13b|r14b|r15)(?-i)\\b" - identifier: "\\b(?i)(cw|sw|tw|fp_ds|fp_opc|fp_ip|fp_dp|fp_cs|cs|ss|ds|es|fs|gs|gdtr|idtr|tr|ldtr|ax|bx|cx|dx|bp|si|r8w|r9w|r10w|r11w|di|sp|r12w|r13w|r14w|r15w|ip)(?-i)\\b" - identifier: "\\b(?i)(fp_dp|fp_ip|eax|ebx|ecx|edx|ebp|esi|r8d|r9d|r10d|r11d|edi|esp|r12d|r13d|r14d|r15d|eip|eflags|mxcsr)(?-i)\\b" - identifier: "\\b(?i)(mm0|mm1|mm2|mm3|mm4|mm5|mm6|mm7|rax|rbx|rcx|rdx|rbp|rsi|r8|r9|r10|r11|rdi|rsp|r12|r13|r14|r15|rip|rflags|cr0|cr1|cr2|cr3|cr4|cr5|cr6|cr7|cr8|cr9|cr10|cr11|cr12|cr13|cr14|cr15|msw|dr0|dr1|dr2|dr3|r4|dr5|dr6|dr7|dr8|dr9|dr10|dr11|dr12|dr13|dr14|dr15)(?-i)\\b" - identifier: "\\b(?i)(st0|st1|st2|st3|st4|st5|st6|st7)(?-i)\\b" - identifier: "\\b(?i)(xmm0|xmm1|xmm2|xmm3|xmm4|xmm5|xmm6|xmm7|xmm8|xmm9|xmm10|xmm11|xmm12|xmm13|xmm14|xmm15)(?-i)\\b" - identifier: "\\b(?i)(ymm0|ymm1|ymm2|ymm3|ymm4|ymm5|ymm6|ymm7|ymm8|ymm9|ymm10|ymm11|ymm12|ymm13|ymm14|ymm15)(?-i)\\b" - identifier: "\\b(?i)(zmm0|zmm1|zmm2|zmm3|zmm4|zmm5|zmm6|zmm7|zmm8|zmm9|zmm10|zmm11|zmm12|zmm13|zmm14|zmm15|zmm16|zmm17|zmm18|zmm19|zmm20|zmm21|zmm22|zmm23|zmm24|zmm25|zmm26|zmm27|zmm28|zmm29|zmm30|zmm31)(?-i)\\b" ## Constants # Number - it works - constant.number: "\\b(|h|A|0x)+[0-9]+(|h|A)+\\b" - constant.number: "\\b0x[0-9 a-f A-F]+\\b" ## Preprocessor (NASM) - preproc: "%+(\\+|\\?|\\?\\?|)[a-z A-Z 0-9]+" - preproc: "%\\[[. a-z A-Z 0-9]*\\]" ## Other - statement: "\\b(?i)(extern|global|section|segment|_start|\\.text|\\.data|\\.bss)(?-i)\\b" - statement: "\\b(?i)(db|dw|dd|dq|dt|ddq|do)(?-i)\\b" - identifier: "[a-z A-Z 0-9 _]+:" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: ";" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" ## C-like comments (supported by some assemblers) - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/asciidoc.yaml0000664000175000017510000000235215125206537021720 0ustar nileshnileshfiletype: asciidoc detect: filename: "\\.(asc|asciidoc|adoc)$" rules: # main header - preproc: "^====+$" # h1 - statement: "^==[[:space:]].*$" - statement: "^----+$" # h2 - symbol: "^===[[:space:]].*$" - symbol: "^~~~~+$" # h4 - type: "^====[[:space:]].*$" - type: "^\\^\\^\\^\\^+$" # h5 - constant: "^=====[[:space:]].*$" - constant: "^\\+\\+\\+\\++$" # attributes - type.keyword: ":.*:" - identifier.macro: "\\{[a-z0-9]*\\}" - identifier: "\\\\\\{[a-z0-9]*\\}" - identifier: "\\+\\+\\+\\{[a-z0-9]*\\}\\+\\+\\+" # Paragraph Title - statement: "^\\..*$" # source - identifier: "^\\[(source,.+|NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\]" # Other markup - constant.string: ".*[[:space:]]\\+$" - constant.string: "_[^_]+_" - constant.string: "\\*[^\\*]+\\*" - constant.string: "\\+[^\\+]+\\+" - constant.string: "`[^`]+`" - constant.string: "\\^[^\\^]+\\^" - constant.string: "~[^~]+~" - constant.string: "'[^']+'" - constant: "`{1,2}[^']+'{1,2}" # bullets - symbol: "^[[:space:]]*[\\*\\.-]{1,5}[[:space:]]" # anchors - "bold default": "\\[\\[.*\\]\\]" - "bold default": "<<.*>>" zyedidia-micro-6a62575/runtime/syntax/arduino.yaml0000664000175000017510000000541615125206537021607 0ustar nileshnileshfiletype: ino detect: filename: "\\.ino$" rules: - identifier: "\\b[A-Z_][0-9A-Z_]+\\b" ## Sized (u)int types - type: "\\b((s?size)|((u_?)?int(8|16|32|64|ptr)))_t\\b" ## Constants - constant: "(?i)\\b(HIGH|LOW|INPUT|OUTPUT)\\b" ## Serial Print - constant: "(?i)\\b(DEC|BIN|HEX|OCT|BYTE)\\b" ## PI Constants - constant: "(?i)\\b(PI|HALF_PI|TWO_PI)\\b" ## ShiftOut - constant: "(?i)\\b(LSBFIRST|MSBFIRST)\\b" ## Attach Interrupt - constant: "(?i)\\b(CHANGE|FALLING|RISING)\\b" ## Analog Reference - constant: "(?i)\\b(DEFAULT|EXTERNAL|INTERNAL|INTERNAL1V1|INTERNAL2V56)\\b" ## === FUNCTIONS === ## ## Data Types - type: "\\b(boolean|byte|char|float|int|long|word)\\b" ## Control Structions - statement: "\\b(case|class|default|do|double|else|false|for|if|new|null|private|protected|public|short|signed|static|String|switch|this|throw|try|true|unsigned|void|while)\\b" - statement: "\\b(goto|continue|break|return)\\b" ## Math - identifier: "\\b(abs|acos|asin|atan|atan2|ceil|constrain|cos|degrees|exp|floor|log|map|max|min|radians|random|randomSeed|round|sin|sq|sqrt|tan)\\b" ## Bits & Bytes - identifier: "\\b(bitRead|bitWrite|bitSet|bitClear|bit|highByte|lowByte)\\b" ## Analog I/O - identifier: "\\b(analogReference|analogRead|analogWrite)\\b" ## External Interrupts - identifier: "\\b(attachInterrupt|detachInterrupt)\\b" ## Time - identifier: "\\b(delay|delayMicroseconds|millis|micros)\\b" ## Digital I/O - identifier: "\\b(pinMode|digitalWrite|digitalRead)\\b" ## Interrupts - identifier: "\\b(interrupts|noInterrupts)\\b" ## Advanced I/O - identifier: "\\b(noTone|pulseIn|shiftIn|shiftOut|tone)\\b" ## Serial - identifier: "\\b(Serial|Serial1|Serial2|Serial3|begin|end|peek|read|print|println|available|flush)\\b" ## Structure - identifier: "\\b(setup|loop)\\b" ## - statement: "^[[:space:]]*#[[:space:]]*(define|include(_next)?|(un|ifn?)def|endif|el(if|se)|if|warning|error|pragma)" ## GCC builtins - constant: "(__attribute__[[:space:]]*\\(\\([^)]*\\)\\)|__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__)" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - constant.string: start: "'" end: "'" skip: "\\\\." rules: - preproc: "..+" - constant.specialChar: "\\\\." - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/apacheconf.yaml0000664000175000017510000001457715125206537022245 0ustar nileshnileshfiletype: apacheconf detect: filename: "httpd\\.conf|mime\\.types|vhosts\\.d\\\\*|\\.htaccess" rules: - identifier: "(AcceptMutex|AcceptPathInfo|AccessFileName|Action|AddAlt|AddAltByEncoding|AddAltByType|AddCharset|AddDefaultCharset|AddDescription|AddEncoding)" - identifier: "(AddHandler|AddIcon|AddIconByEncoding|AddIconByType|AddInputFilter|AddLanguage|AddModuleInfo|AddOutputFilter|AddOutputFilterByType|AddType|Alias|AliasMatch)" - identifier: "(Allow|AllowCONNECT|AllowEncodedSlashes|AllowOverride|Anonymous|Anonymous_Authoritative|Anonymous_LogEmail|Anonymous_MustGiveEmail|Anonymous_NoUserID)" - identifier: "(Anonymous_VerifyEmail|AssignUserID|AuthAuthoritative|AuthDBMAuthoritative|AuthDBMGroupFile|AuthDBMType|AuthDBMUserFile|AuthDigestAlgorithm)" - identifier: "(AuthDigestDomain|AuthDigestFile|AuthDigestGroupFile|AuthDigestNcCheck|AuthDigestNonceFormat|AuthDigestNonceLifetime|AuthDigestQop|AuthDigestShmemSize)" - identifier: "(AuthGroupFile|AuthLDAPAuthoritative|AuthLDAPBindDN|AuthLDAPBindPassword|AuthLDAPCharsetConfig|AuthLDAPCompareDNOnServer|AuthLDAPDereferenceAliases)" - identifier: "(AuthLDAPEnabled|AuthLDAPFrontPageHack|AuthLDAPGroupAttribute|AuthLDAPGroupAttributeIsDN|AuthLDAPRemoteUserIsDN|AuthLDAPUrl|AuthName|AuthType|AuthUserFile)" - identifier: "(BrowserMatch|BrowserMatchNoCase|BS2000Account|BufferedLogs|CacheDefaultExpire|CacheDirLength|CacheDirLevels|CacheDisable|CacheEnable|CacheExpiryCheck)" - identifier: "(CacheFile|CacheForceCompletion|CacheGcClean|CacheGcDaily|CacheGcInterval|CacheGcMemUsage|CacheGcUnused|CacheIgnoreCacheControl|CacheIgnoreHeaders)" - identifier: "(CacheIgnoreNoLastMod|CacheLastModifiedFactor|CacheMaxExpire|CacheMaxFileSize|CacheMinFileSize|CacheNegotiatedDocs|CacheRoot|CacheSize|CacheTimeMargin)" - identifier: "(CGIMapExtension|CharsetDefault|CharsetOptions|CharsetSourceEnc|CheckSpelling|ChildPerUserID|ContentDigest|CookieDomain|CookieExpires|CookieLog|CookieName)" - identifier: "(CookieStyle|CookieTracking|CoreDumpDirectory|CustomLog|Dav|DavDepthInfinity|DavLockDB|DavMinTimeout|DefaultIcon|DefaultLanguage|DefaultType)" - identifier: "(DeflateBufferSize|DeflateCompressionLevel|DeflateFilterNote|DeflateMemLevel|DeflateWindowSize|Deny|Directory|DirectoryIndex|DirectoryMatch|DirectorySlash)" - identifier: "(DocumentRoot|DumpIOInput|DumpIOOutput|EnableExceptionHook|EnableMMAP|EnableSendfile|ErrorDocument|ErrorLog|Example|ExpiresActive|ExpiresByType)" - identifier: "(ExpiresDefault|ExtendedStatus|ExtFilterDefine|ExtFilterOptions|FileETag|Files|FilesMatch|ForceLanguagePriority|ForceType|ForensicLog|Group|Header)" - identifier: "(HeaderName|HostnameLookups|IdentityCheck|IfDefine|IfModule|IfVersion|ImapBase|ImapDefault|ImapMenu|Include|IndexIgnore|IndexOptions|IndexOrderDefault)" - identifier: "(ISAPIAppendLogToErrors|ISAPIAppendLogToQuery|ISAPICacheFile|ISAPIFakeAsync|ISAPILogNotSupported|ISAPIReadAheadBuffer|KeepAlive|KeepAliveTimeout)" - identifier: "(LanguagePriority|LDAPCacheEntries|LDAPCacheTTL|LDAPConnectionTimeout|LDAPOpCacheEntries|LDAPOpCacheTTL|LDAPSharedCacheFile|LDAPSharedCacheSize)" - identifier: "(LDAPTrustedCA|LDAPTrustedCAType|Limit|LimitExcept|LimitInternalRecursion|LimitRequestBody|LimitRequestFields|LimitRequestFieldSize|LimitRequestLine)" - identifier: "(LimitXMLRequestBody|Listen|ListenBackLog|LoadFile|LoadModule|Location|LocationMatch|LockFile|LogFormat|LogLevel|MaxClients|MaxKeepAliveRequests)" - identifier: "(MaxMemFree|MaxRequestsPerChild|MaxRequestsPerThread|MaxSpareServers|MaxSpareThreads|MaxThreads|MaxThreadsPerChild|MCacheMaxObjectCount|MCacheMaxObjectSize)" - identifier: "(MCacheMaxStreamingBuffer|MCacheMinObjectSize|MCacheRemovalAlgorithm|MCacheSize|MetaDir|MetaFiles|MetaSuffix|MimeMagicFile|MinSpareServers|MinSpareThreads)" - identifier: "(MMapFile|ModMimeUsePathInfo|MultiviewsMatch|NameVirtualHost|NoProxy|NumServers|NWSSLTrustedCerts|NWSSLUpgradeable|Options|Order|PassEnv|PidFile)" - identifier: "(ProtocolEcho|Proxy|ProxyBadHeader|ProxyBlock|ProxyDomain|ProxyErrorOverride|ProxyIOBufferSize|ProxyMatch|ProxyMaxForwards|ProxyPass|ProxyPassReverse)" - identifier: "(ProxyPreserveHost|ProxyReceiveBufferSize|ProxyRemote|ProxyRemoteMatch|ProxyRequests|ProxyTimeout|ProxyVia|ReadmeName|Redirect|RedirectMatch)" - identifier: "(RedirectPermanent|RedirectTemp|RemoveCharset|RemoveEncoding|RemoveHandler|RemoveInputFilter|RemoveLanguage|RemoveOutputFilter|RemoveType|RequestHeader)" - identifier: "(Require|RewriteBase|RewriteCond|RewriteEngine|RewriteLock|RewriteLog|RewriteLogLevel|RewriteMap|RewriteOptions|RewriteRule|RLimitCPU|RLimitMEM|RLimitNPROC)" - identifier: "(Satisfy|ScoreBoardFile|Script|ScriptAlias|ScriptAliasMatch|ScriptInterpreterSource|ScriptLog|ScriptLogBuffer|ScriptLogLength|ScriptSock|SecureListen)" - identifier: "(SendBufferSize|ServerAdmin|ServerAlias|ServerLimit|ServerName|ServerPath|ServerRoot|ServerSignature|ServerTokens|SetEnv|SetEnvIf|SetEnvIfNoCase|SetHandler)" - identifier: "(SetInputFilter|SetOutputFilter|SSIEndTag|SSIErrorMsg|SSIStartTag|SSITimeFormat|SSIUndefinedEcho|SSLCACertificateFile|SSLCACertificatePath)" - identifier: "(SSLCARevocationFile|SSLCARevocationPath|SSLCertificateChainFile|SSLCertificateFile|SSLCertificateKeyFile|SSLCipherSuite|SSLEngine|SSLMutex|SSLOptions)" - identifier: "(SSLPassPhraseDialog|SSLProtocol|SSLProxyCACertificateFile|SSLProxyCACertificatePath|SSLProxyCARevocationFile|SSLProxyCARevocationPath|SSLProxyCipherSuite)" - identifier: "(SSLProxyEngine|SSLProxyMachineCertificateFile|SSLProxyMachineCertificatePath|SSLProxyProtocol|SSLProxyVerify|SSLProxyVerifyDepth|SSLRandomSeed|SSLRequire)" - identifier: "(SSLRequireSSL|SSLSessionCache|SSLSessionCacheTimeout|SSLUserName|SSLVerifyClient|SSLVerifyDepth|StartServers|StartThreads|SuexecUserGroup|ThreadLimit)" - identifier: "(ThreadsPerChild|ThreadStackSize|TimeOut|TraceEnable|TransferLog|TypesConfig|UnsetEnv|UseCanonicalName|User|UserDir|VirtualDocumentRoot)" - identifier: "(VirtualDocumentRootIP|VirtualHost|VirtualScriptAlias|VirtualScriptAliasIP|Win32DisableAcceptEx|XBitHack)" - symbol.tag: "<[^>]+>" - identifier: ")" - constant.string: start: "\"" end: "\"" skip: "\\\\." rules: - constant.specialChar: "\\\\." - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/ada.yaml0000664000175000017510000000276515125206537020677 0ustar nileshnileshfiletype: ada detect: filename: "(\\.ads$|\\.adb$|\\.ada$)" rules: # Operators - symbol.operator: ([.:;,+*|=!?\\%]|<|>|/|-|&) - symbol.brackets: "[(){}]|\\[|\\]" # keyword.reserved - statement.reserved: \b(abort|abs|abstract|accept|access|aliased|all|and|array|at|begin|body|case)\b - statement.reserved: \b(constant|declare|delay|delta|digits|do|else|elsif|end|entry|exception|exit|for|function)\b - statement.reserved: \b(generic|goto|if|in|interface|is|limited|loop|mod|new|not|null|of|or|others|out|overriding)\b - statement.reserved: \b(package|pragma|private|procedure|protected|raise|range|record|rem|renames|return|requeue)\b - statement.reserved: \b(reverse|select|separate|some|subtype|synchronized|tagged|task|terminate|then|type|until)\b - statement.reserved: \b(use|when|while|with|xor)\b # Constant - constant.bool: \b(TRUE|FALSE) - constant.number: ([0-9]+) # Storage Types - type.storage: \b(INTEGER|NATURAL|POSITIVE|FLOAT|CHARACTER|STRING)\b - type.storage: \b(LONG_INTEGER|SHORT_INTEGER|LONG_FLOAT|SHORT_FLOAT)\b #Character - constant.string.char: \'.\' # String - constant.string: start: \" end: \" skip: \\. rules: - constant.specialChar: (\\0|\\\\|\\t|\\n|\\r|\\"|\\') - constant.interpolation: \\\([[:graph:]]*\) - constant.unicode: \\u\{[[:xdigit:]]+} # Line Comment - comment.line: "--.*" # Todo - todo: "(TODO|XXX|FIXME):?" zyedidia-micro-6a62575/runtime/syntax/README.md0000664000175000017510000000415315125206537020536 0ustar nileshnilesh# Syntax Files Here are micro's syntax files. Each yaml file specifies how to detect the filetype based on file extension or header (first line of the line). In addition, a signature can be provided to help resolving ambiguities when multiple matching filetypes are detected. Then there are patterns and regions linked to highlight groups which tell micro how to highlight that filetype. You can read more about how to write syntax files (and colorschemes) in the [colors](../help/colors.md) documentation. # Legacy '.micro' filetype Micro used to use the `.micro` filetype for syntax files which is no longer supported. If you have `.micro` syntax files that you would like to convert to the new filetype, you can use the [`syntax_converter.go`](./syntax_converter.go) program (also located in this directory): ``` $ go run syntax_converter.go c.micro > c.yaml ``` Most of the syntax files here have been converted using that tool. Note that the tool isn't perfect and though it is unlikely, you may run into some small issues that you will have to fix manually (about 4 files from this directory had issues after being converted). # Micro syntax highlighting files These are the syntax highlighting files for micro. To install them, just put all the syntax files in `~/.config/micro/syntax`. They are taken from Nano, specifically from [this repository](https://github.com/scopatz/nanorc). Micro syntax files are almost identical to Nano's, except for some key differences: * Micro does not use `icolor`. Instead, for a case insensitive match, use the case insensitive flag (`i`) in the regular expression * For example, `icolor green ".*"` would become `color green "(?i).*"` # Using with colorschemes Not all of these files have been converted to use micro's colorscheme feature. Most of them just hardcode the colors, which can be problematic depending on the colorscheme you use. Here is a list of the files that have been converted to properly use colorschemes: * vi * go * c * d * markdown * html * lua * swift * rust * java * javascript * pascal * python * ruby * sh * git * tex * solidity # License See [LICENSE](LICENSE). zyedidia-micro-6a62575/runtime/syntax/PowerShell.yaml0000664000175000017510000001164415125206537022232 0ustar nileshnilesh# PowerShell syntax highlighting file for micro - https://micro-editor.github.io/ # PowerShell syntax taken from: https://github.com/PowerShell/EditorSyntax filetype: powershell detect: filename: "\\.ps(1|m1|d1)$" rules: # - comment.block: # Block Comment # - comment.doc: # Doc Comment # - comment.line: # Line Comment # - comment.shebang: # Shebang Line # - constant: # Constant # - constant.bool: # Constant (true, false) # - constant.interpolation: # - constant.number: # Constant (null) # - constant.specialChar: # - constant.string: # String # - constant.string.char: # - constant.string.url: # Uri # - constant.unicode: # - identifier: # Also used for functions # - identifier.class: # Also used for functions # - identifier.macro: # - identifier.var: # - preproc: # Preprocessor # - preproc.DebugIdentifier: # Preprocessor # - preproc.shebang: # The #! at the beginning of a file that tells the os what script interpreter to use # - special: # Special (global|local|private|script|using|workflow) # - statement: # Statements Keywords # - statement.built_in: # - statement.declaration: # Declaration Keywords # - statement.meta: # Meta # - statement.reserved: # Reserved Keywords # - symbol # - symbol.brackets: # {}()[] and sometimes <> # - symbol.operator: # Operators # - symbol.tag: # For html tags, among other things # - type # - type.collections: # Collections (array, hashtable) # - type.ctypes: # CTypes (CBool, CChar, etc.) # - type.keyword: # If you want a special highlight for keywords like 'private' # - type.storage: # Storage Types (int, uint, string, etc.) # Class - identifier.class: "class +[A-Za-z0-9]+ *((:) +[A-Za-z0-9.]+)?" - identifier.class: "(function)(?:([[:space:]][A-Za-z0-9]+[[:space:]]*))" # Verbs taken from PwSh 6.0.2 - identifier: "(Add|Approve|Assert|Backup|Block|Build|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy)[-][A-Za-z0-9]+" - identifier: "(Debug|Deny|Deploy|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|Format|Get|Grant|Group|Hide)[-][A-Za-z0-9]+" - identifier: "(Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Mount|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push)[-][A-Za-z0-9]+" - identifier: "(Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke)[-][A-Za-z0-9]+" - identifier: "(Save|Search|Select|Send|Set|Show|Skip|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Test|Trace)[-][A-Za-z0-9]+" - identifier: "(Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Write)[-][A-Za-z0-9]+" - identifier.var: "\\$(?i)((Global|Local|Private|Script|Using|Workflow)[:])?[A-Za-z0-9]*" # Expression and types - type: "\\[\\b([A-Za-z]+|[A-Za-z]+[0-9]+)\\b\\]" # Keywords - statement: "\\b(alias|as|begin|break|catch|continue|data|default|define|do|dynamicparam)\\b" - statement: "\\b(else|elseif|end|exit|finally|for|foreach|foreach-object|from|if|in|inlinescript)\\b" - statement: "\\b(parallel|param|process|return|switch|throw|trap|try|until|using|var|where|where-object|while)\\b" # Special Keywords - special: "\\b(break|continue|exit)\\b" - symbol.brackets: "(\\{|\\})" - symbol.brackets: "(\\(|\\))" - symbol.brackets: "(\\[|\\])" - symbol.operator: "[\\-+/*=<>?:!~%&|]" - symbol.operator: "[[:space:]][-](ne|eq|gt|ge|lt|le|like|notlike|match|notmatch|contains|notcontains|in|notin|replace|is|isnot)[[:space:]]" # Constants - constant.bool: "\\b\\$(true|false|null)\\b" - constant.number: "\\b([0-9._]+|0x[A-Fa-f0-9_]+|0b[0-1_]+)[FL]?\\b" # Expression Mode String - constant.string: start: "\"" end: "\"" #skip: "\\\\." rules: - constant.specialChar: "\\\\([btnfr]|'|\\\"|\\\\)" - constant.specialChar: "\\\\u[A-Fa-f0-9]{4}" # Argument Mode String - constant.string: start: "'" end: "'" #skip: "\\\\." rules: - constant.specialChar: "\\\\([btnfr]|'|\\\"|\\\\)" - constant.specialChar: "\\\\u[A-Fa-f0-9]{4}" # Line Comment - comment: start: "#" end: "$" rules: - todo: "(TODO|XXX|FIXME|BUG):?" # Block Comment - comment: start: "<#" end: "#>" rules: - todo: "(TODO|XXX|FIXME|BUG):?" # Embedded C# - default: start: "@\"" end: "\"@" rules: - include: "csharp" # Todo - todo: "(TODO|XXX|FIXME|BUG):?" zyedidia-micro-6a62575/runtime/syntax/LICENSE0000664000175000017510000000215615125206537020265 0ustar nileshnileshMicro's syntax files are licensed under the MIT "Expat" License: Copyright (c) 2020: Zachary Yedidia, et al. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. zyedidia-micro-6a62575/runtime/runtime_test.go0000664000175000017510000000043015125206537020774 0ustar nileshnileshpackage config import ( "testing" "github.com/stretchr/testify/assert" ) func TestAssetDir(t *testing.T) { t.Parallel() // Test AssetDir entries, err := AssetDir("syntax") assert.NoError(t, err) assert.Contains(t, entries, "go.yaml") assert.True(t, len(entries) > 5) } zyedidia-micro-6a62575/runtime/runtime.go0000664000175000017510000000131715125206537017742 0ustar nileshnileshpackage config import ( "embed" "path/filepath" "strings" ) //go:generate go run syntax/make_headers.go syntax //go:embed colorschemes help plugins syntax var runtime embed.FS func fixPath(name string) string { return strings.TrimLeft(filepath.ToSlash(name), "runtime/") } // AssetDir lists file names in folder func AssetDir(name string) ([]string, error) { name = fixPath(name) entries, err := runtime.ReadDir(name) if err != nil { return nil, err } names := make([]string, len(entries)) for i, entry := range entries { names[i] = entry.Name() } return names, nil } // Asset returns a file content func Asset(name string) ([]byte, error) { name = fixPath(name) return runtime.ReadFile(name) } zyedidia-micro-6a62575/runtime/plugins/0000775000175000017510000000000015125206537017407 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/status/0000775000175000017510000000000015125206537020732 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/status/status.lua0000664000175000017510000000265615125206537022771 0ustar nileshnileshVERSION = "1.0.0" local micro = import("micro") local buffer = import("micro/buffer") local config = import("micro/config") local shell = import("micro/shell") local filepath = import("filepath") local humanize = import("humanize") local strings = import("strings") function init() micro.SetStatusInfoFn("status.branch") micro.SetStatusInfoFn("status.hash") micro.SetStatusInfoFn("status.paste") micro.SetStatusInfoFn("status.vcol") micro.SetStatusInfoFn("status.lines") micro.SetStatusInfoFn("status.bytes") micro.SetStatusInfoFn("status.size") config.AddRuntimeFile("status", config.RTHelp, "help/status.md") end function lines(b) return tostring(b:LinesNum()) end function vcol(b) return tostring(b:GetActiveCursor():GetVisualX(false)) end function bytes(b) return tostring(b:Size()) end function size(b) return humanize.Bytes(b:Size()) end local function parseRevision(b, opt) if b.Type.Kind ~= buffer.BTInfo then local dir = filepath.Dir(b.Path) local str, err = shell.ExecCommand("git", "-C", dir, "rev-parse", opt, "HEAD") if err == nil then return strings.TrimSpace(str) end end return "" end function branch(b) return parseRevision(b, "--abbrev-ref") end function hash(b) return parseRevision(b, "--short") end function paste(b) if config.GetGlobalOption("paste") then return "PASTE " end return "" end zyedidia-micro-6a62575/runtime/plugins/status/help/0000775000175000017510000000000015125206537021662 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/status/help/status.md0000664000175000017510000000167115125206537023534 0ustar nileshnilesh# Status The status plugin provides some functions for modifying the status line. Using the `statusformatl` and `statusformatr` options, the exact contents of the status line can be modified. Please see the documentation for those options (`> help options`) for more information. This plugin provides functions that can be used in the status line format: * `status.branch`: returns the name of the current git branch in the repository where the file is located. * `status.hash`: returns the hash of the current git commit in the repository where the file is located. * `status.paste`: returns "" if the paste option is disabled and "PASTE" if it is enabled. * `status.lines`: returns the number of lines in the buffer. * `status.vcol`: returns the visual column number of the cursor. * `status.bytes`: returns the number of bytes in the current buffer. * `status.size`: returns the size of the current buffer in a human-readable format. zyedidia-micro-6a62575/runtime/plugins/literate/0000775000175000017510000000000015125206537021220 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/literate/literate.lua0000664000175000017510000000374215125206537023542 0ustar nileshnileshVERSION = "1.0.0" local config = import("micro/config") function startswith(str, start) return string.sub(str,1,string.len(start))==start end function endswith(str, endStr) return endStr=='' or string.sub(str,-string.len(endStr))==endStr end function split(string, sep) local sep, fields = sep or ":", {} local pattern = string.format("([^%s]+)", sep) string:gsub(pattern, function(c) fields[#fields+1] = c end) return fields end function onBufferOpen(buf) if not endswith(buf.Path, ".lit") then return end local codetype = "unknown" for i=1,buf:LinesNum() do local line = buf:Line(i-1) if startswith(line, "@code_type") then codetype = split(line, " ")[2] break end end local syntaxFile = "" syntaxFile = syntaxFile .. "filetype: literate-" .. codetype .. "\n" syntaxFile = syntaxFile .. "detect:\n" syntaxFile = syntaxFile .. " filename: \"\\\\.lit$\"\n" syntaxFile = syntaxFile .. "rules:\n" syntaxFile = syntaxFile .. " - include: \"markdown\"\n" syntaxFile = syntaxFile .. " - special: \"^(@s|@title|@code_type|@comment_type|@include|@change|@change_end)\"\n" syntaxFile = syntaxFile .. " - special: \"(@add_css|@overwrite_css|@colorscheme|@compiler|@error_format|@book)\"\n" syntaxFile = syntaxFile .. " - default:\n" syntaxFile = syntaxFile .. " start: \"---.*$\"\n" syntaxFile = syntaxFile .. " end: \"---$\"\n" syntaxFile = syntaxFile .. " limit-group: \"identifier\"\n" syntaxFile = syntaxFile .. " rules:\n" syntaxFile = syntaxFile .. " - special:\n" syntaxFile = syntaxFile .. " start: \"@\\\\{\"\n" syntaxFile = syntaxFile .. " end: \"\\\\}\"\n" syntaxFile = syntaxFile .. " - include: " .. codetype .. "\n" config.AddRuntimeFileFromMemory(config.RTSyntax, "literate.yaml", syntaxFile) config.Reload() buf:UpdateRules() end zyedidia-micro-6a62575/runtime/plugins/literate/README.md0000664000175000017510000000034215125206537022476 0ustar nileshnilesh# Literate Micro Support for reading `.lit` files from [zyedidia/Literate](https://github.com/zyedidia/Literate). This plugin will automatically detect the filetype and highlight the correct language inside the code blocks. zyedidia-micro-6a62575/runtime/plugins/linter/0000775000175000017510000000000015125206537020704 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/linter/linter.lua0000664000175000017510000002101115125206537022677 0ustar nileshnileshVERSION = "1.0.0" local micro = import("micro") local runtime = import("runtime") local filepath = import("path/filepath") local shell = import("micro/shell") local buffer = import("micro/buffer") local config = import("micro/config") local util = import("micro/util") local os = import("os") local linters = {} -- creates a linter entry, call from within an initialization function, not -- directly at initial load time -- -- name: name of the linter -- filetype: filetype to check for to use linter -- cmd: main linter process that is executed -- args: arguments to pass to the linter process -- use %f to refer to the current file name -- use %d to refer to the current directory name -- errorformat: how to parse the linter/compiler process output -- %f: file, %l: line number, %m: error/warning message -- os: list of OSs this linter is supported or unsupported on -- optional param, default: {} -- whitelist: should the OS list be a blacklist (do not run the linter for these OSs) -- or a whitelist (only run the linter for these OSs) -- optional param, default: false (should blacklist) -- domatch: should the filetype be interpreted as a lua pattern to match with -- the actual filetype, or should the linter only activate on an exact match -- optional param, default: false (require exact match) -- loffset: line offset will be added to the line number returned by the linter -- useful if the linter returns 0-indexed lines -- optional param, default: 0 -- coffset: column offset will be added to the col number returned by the linter -- useful if the linter returns 0-indexed columns -- optional param, default: 0 -- callback: function to call before executing the linter, if it returns -- false the lint is canceled. The callback is passed the buf. -- optional param, default: nil function makeLinter(name, filetype, cmd, args, errorformat, os, whitelist, domatch, loffset, coffset, callback) if linters[name] == nil then linters[name] = {} linters[name].filetype = filetype linters[name].cmd = cmd linters[name].args = args linters[name].errorformat = errorformat linters[name].os = os or {} linters[name].whitelist = whitelist or false linters[name].domatch = domatch or false linters[name].loffset = loffset or 0 linters[name].coffset = coffset or 0 linters[name].callback = callback or nil end end function removeLinter(name) linters[name] = nil end function preinit() local devnull = "/dev/null" if runtime.GOOS == "windows" then devnull = "NUL" end makeLinter("gcc", "c", "gcc", {"-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m") makeLinter("g++", "c++", "g++", {"-fsyntax-only","-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m") makeLinter("dmd", "d", "dmd", {"-color=off", "-o-", "-w", "-wi", "-c", "%f"}, "%f%(%l%):.+: %m") makeLinter("ldc2", "d", "ldc2", {"--o-", "--vcolumns", "-w", "-c", "%f"}, "%f%(%l,%c%):[^:]+: %m") makeLinter("gdc", "d", "gdc", {"-fsyntax-only","-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m") makeLinter("eslint", "javascript", "eslint", {"-f","compact","%f"}, "%f: line %l, col %c, %m") makeLinter("gobuild", "go", "go", {"build", "-o", devnull, "%d"}, "%f:%l:%c:? %m") makeLinter("govet", "go", "go", {"vet"}, "%f:%l:%c: %m") makeLinter("clippy", "rust", "cargo", {"clippy", "--message-format", "short"}, "%f:%l:%c: %m") makeLinter("hlint", "haskell", "hlint", {"%f"}, "%f:%(?%l[,:]%c%)?.-: %m") makeLinter("javac", "java", "javac", {"-d", "%d", "%f"}, "%f:%l: error: %m") makeLinter("jshint", "javascript", "jshint", {"%f"}, "%f: line %l,.+, %m") makeLinter("literate", "literate", "lit", {"-c", "%f"}, "%f:%l:%m", {}, false, true) makeLinter("luacheck", "lua", "luacheck", {"--no-color", "%f"}, "%f:%l:%c: %m") makeLinter("nim", "nim", "nim", {"check", "--listFullPaths", "--stdout", "--hints:off", "%f"}, "%f.%l, %c. %m") makeLinter("clang", "objective-c", "xcrun", {"clang", "-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m") makeLinter("pyflakes", "python", "pyflakes", {"%f"}, "%f:%l:.-:? %m") makeLinter("mypy", "python", "mypy", {"%f"}, "%f:%l: %m") makeLinter("pylint", "python", "pylint", {"--output-format=parseable", "--reports=no", "%f"}, "%f:%l: %m") makeLinter("ruff", "python", "ruff", {"check", "--output-format=concise", "%f"}, "%f:%l:%c: %m") makeLinter("flake8", "python", "flake8", {"%f"}, "%f:%l:%c: %m") makeLinter("shfmt", "shell", "shfmt", {"%f"}, "%f:%l:%c: %m") makeLinter("shellcheck", "shell", "shellcheck", {"-f", "gcc", "%f"}, "%f:%l:%c:.+: %m") makeLinter("swiftc", "swift", "xcrun", {"swiftc", "%f"}, "%f:%l:%c:.+: %m", {"darwin"}, true) makeLinter("swiftc-linux", "swift", "swiftc", {"%f"}, "%f:%l:%c:.+: %m", {"linux"}, true) makeLinter("yaml", "yaml", "yamllint", {"--format", "parsable", "%f"}, "%f:%l:%c:.+ %m") makeLinter("nix-linter", "nix", "nix-linter", {"%f"}, "%m at %f:%l:%c", {"linux"}, true) config.MakeCommand("lint", function(bp, args) bp:Save() runLinter(bp.Buf) end, config.NoComplete) config.AddRuntimeFile("linter", config.RTHelp, "help/linter.md") end function contains(list, element) for k, v in pairs(list) do if v == element then return true end end return false end function checkFtMatch(ft, v) local ftmatch = ft == v.filetype if v.domatch then ftmatch = string.match(ft, v.filetype) end local hasOS = contains(v.os, runtime.GOOS) if not hasOS and v.whitelist then ftmatch = false end if hasOS and not v.whitelist then ftmatch = false end return ftmatch end function runLinter(buf) local ft = buf:FileType() local file = buf.Path local dir = "." .. util.RuneStr(os.PathSeparator) .. filepath.Dir(file) for k, v in pairs(linters) do if checkFtMatch(ft, v) then local args = {} for k, arg in pairs(v.args) do args[k] = arg:gsub("%%f", file):gsub("%%d", dir) end lint(buf, k, v.cmd, args, v.errorformat, v.loffset, v.coffset, v.callback) end end end function onSave(bp) runLinter(bp.Buf) return true end function onBufferOptionChanged(buf, option, old, new) if option == "filetype" then if old ~= new then for k, v in pairs(linters) do if checkFtMatch(old, v) then buf:ClearMessages(k) end end end end return true end function lint(buf, linter, cmd, args, errorformat, loff, coff, callback) buf:ClearMessages(linter) if callback ~= nil then if not callback(buf) then return end end shell.JobSpawn(cmd, args, nil, nil, onExit, buf, linter, errorformat, loff, coff) end function onExit(output, args) local buf, linter, errorformat, loff, coff = args[1], args[2], args[3], args[4], args[5] local lines = split(output, "\n") local regex = errorformat:gsub("%%f", "(..-)"):gsub("%%l", "(%d+)"):gsub("%%c", "(%d+)"):gsub("%%m", "(.+)") for _,line in ipairs(lines) do -- Trim whitespace line = line:match("^%s*(.+)%s*$") if string.find(line, regex) then local file, line, col, msg = string.match(line, regex) local hascol = true if not string.find(errorformat, "%%c") then hascol = false msg = col elseif col == nil then hascol = false end if basename(buf.Path) == basename(file) then local bmsg = nil if hascol then local mstart = buffer.Loc(tonumber(col-1+coff), tonumber(line-1+loff)) local mend = buffer.Loc(tonumber(col+coff), tonumber(line-1+loff)) bmsg = buffer.NewMessage(linter, msg, mstart, mend, buffer.MTError) else bmsg = buffer.NewMessageAtLine(linter, msg, tonumber(line+loff), buffer.MTError) end buf:AddMessage(bmsg) end end end end function split(str, sep) local result = {} local regex = ("([^%s]+)"):format(sep) for each in str:gmatch(regex) do table.insert(result, each) end return result end function basename(file) local sep = "/" if runtime.GOOS == "windows" then sep = "\\" end local name = string.gsub(file, "(.*" .. sep .. ")(.*)", "%2") return name end zyedidia-micro-6a62575/runtime/plugins/linter/help/0000775000175000017510000000000015125206537021634 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/linter/help/linter.md0000664000175000017510000000651115125206537023456 0ustar nileshnilesh# Linter The linter plugin runs a compiler or linter on your source code and parses the resulting output so that the messages and line numbers can be viewed from within micro. By default, the plugin supports the following filetypes and linters: * **c**: gcc * **c++**: g++ * **d**: dmd * **d**: ldc2 * **d**: gdc * **go**: go build * **go**: go vet * **haskell**: hlint * **java**: javac * **javascript**: jshint * **javascript**: eslint * **literate**: lit * **lua**: luacheck * **nim**: nim * **nix**: nix-linter * **objective-c**: clang * **python**: flake8 * **python**: mypy * **python**: pyflakes * **python**: pylint * **python**: ruff * **rust**: cargo clippy * **shell**: shfmt * **shell**: shellcheck * **swift**: swiftc (MacOS and Linux only) * **yaml**: yamllint If the linter plugin is enabled and the file corresponds to one of these filetypes, each time the buffer is saved, or when the `> lint` command is executed, micro will run the corresponding utility in the background and display the messages when it completes. The linter plugin also allows users to extend the supported filetypes. From inside another micro plugin, the function `linter.makeLinter` can be called to register a new filetype. Here is the spec for the `makeLinter` function: `linter.makeLinter(name, filetype, cmd, args, errorformat, os, whitelist, domatch, loffset, coffset, callback)` * **name**: name of the linter * **filetype**: filetype to check for to use linter * **cmd**: main linter process that is executed * **args**: arguments to pass to the linter process * use %f to refer to the current file name * use %d to refer to the current directory name * **errorformat**: how to parse the linter/compiler process output %f: file, %l: line number, %m: error/warning message * **os**: list of OSs this linter is supported or unsupported on optional param, default: {} * **whitelist**: should the OS list be a blacklist (do not run the linter for these OSs) or a whitelist (only run the linter for these OSs) optional param, default: false (should blacklist) * **domatch**: should the filetype be interpreted as a lua pattern to match with the actual filetype, or should the linter only activate on an exact match optional param, default: false (require exact match) * **loffset**: line offset will be added to the line number returned by the linter useful if the linter returns 0-indexed lines optional param, default: 0 * **coffset**: column offset will be added to the col number returned by the linter useful if the linter returns 0-indexed columns optional param, default: 0 * **callback**: function to call before executing the linter, if it returns false the lint is canceled. The callback is passed the buf. optional param, default: nil Below is an example for including a linter for any filetype using the `misspell` linter which checks for misspelled words in a file. ```lua function init() -- uses the default linter plugin -- matches any filetype linter.makeLinter("misspell", "", "misspell", {"%f"}, "%f:%l:%c: %m", {}, false, true) end ``` Here is an example for a more typical use-case, where the linter will only match one filetype (C in this case): ```lua function init() linter.makeLinter("gcc", "c", "gcc", {"-fsyntax-only", "-Wall", "-Wextra", "%f"}, "%f:%l:%c:.+: %m") end ``` zyedidia-micro-6a62575/runtime/plugins/ftoptions/0000775000175000017510000000000015125206537021434 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/ftoptions/ftoptions.lua0000664000175000017510000000060415125206537024164 0ustar nileshnileshVERSION = "1.0.0" function onBufferOpen(b) local ft = b:FileType() if ft == "go" or ft == "makefile" then b:SetOption("tabstospaces", "off") elseif ft == "fish" or ft == "python" or ft == "python2" or ft == "python3" or ft == "yaml" or ft == "nim" then b:SetOption("tabstospaces", "on") end end zyedidia-micro-6a62575/runtime/plugins/diff/0000775000175000017510000000000015125206537020317 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/diff/diff.lua0000664000175000017510000000107415125206537021734 0ustar nileshnileshVERSION = "1.0.0" local os = import("os") local filepath = import("path/filepath") local shell = import("micro/shell") function onBufferOpen(buf) if buf.Settings["diffgutter"] and (not buf.Type.Scratch) and (buf.Path ~= "") then -- check that file exists local _, err = os.Stat(buf.AbsPath) if err == nil then local dirName, fileName = filepath.Split(buf.AbsPath) local diffBase, err = shell.ExecCommand("git", "-C", dirName, "show", "HEAD:./" .. fileName) if err ~= nil then diffBase = buf:Bytes() end buf:SetDiffBase(diffBase) end end end zyedidia-micro-6a62575/runtime/plugins/comment/0000775000175000017510000000000015125206537021051 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/comment/help/0000775000175000017510000000000015125206537022001 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/comment/help/comment.md0000664000175000017510000000354115125206537023770 0ustar nileshnilesh# Comment Plugin The comment plugin provides auto commenting/uncommenting. The default binding to comment/uncomment a line is `Alt-/` and `CtrlUnderscore`, which is equivalent in most terminals to `Ctrl-/`. You can easily modify that in your `bindings.json` file: ```json { "Alt-g": "lua:comment.comment" } ``` You can also execute a command which will do the same thing as the binding: ``` > comment ``` If you have a selection, the plugin will comment all the lines selected. The comment type will be auto detected based on the filetype, but it is only available for certain filetypes: * apacheconf: `# %s` * bat: `:: %s` * c: `// %s` * c++: `// %s` * cmake: `# %s` * conf: `# %s` * crystal: `# %s` * css: `/* %s */` * d: `// %s` * dart: `// %s` * dockerfile: `# %s` * elm: `-- %s` * fish: `# %s` * gdscript: `# %s` * glsl: `// %s` * go: `// %s` * haskell: `-- %s` * html: `` * ini: `; %s` * java: `// %s` * javascript: `// %s` * jinja2: `{# %s #}` * json: `// %s` * julia: `# %s` * kotlin: `// %s` * lua: `-- %s` * markdown: `` * nginx: `# %s` * nim: `# %s` * objc: `// %s` * pascal: `{ %s }` * perl: `# %s` * php: `// %s` * pony: `// %s` * powershell: `# %s` * proto: `// %s` * python: `# %s` * python3: `# %s` * ruby: `# %s` * rust: `// %s` * scala: `// %s` * shell: `# %s` * sql: `-- %s` * swift: `// %s` * tex: `% %s` * toml: `# %s` * twig: `{# %s #}` * v: `// %s` * xml: `` * yaml: `# %s` * zig: `// %s` * zscript: `// %s` * zsh: `# %s` If your filetype is not available here, you can simply modify the `comment.type` option: ``` set comment.type "/* %s */" ``` Or in your `settings.json`: ```json { "*.c": { "comment.type": "/* %s */" } } ``` `commenttype` (without the dot) is the legacy option that is superseded by `comment.type`. `commenttype` is still supported but deprecated. **Use `comment.type` instead.** zyedidia-micro-6a62575/runtime/plugins/comment/comment.lua0000664000175000017510000001565715125206537023234 0ustar nileshnileshVERSION = "1.0.0" local util = import("micro/util") local config = import("micro/config") local buffer = import("micro/buffer") local micro = import("micro") local ft = {} ft["apacheconf"] = "# %s" ft["batch"] = ":: %s" ft["c"] = "// %s" ft["c++"] = "// %s" ft["cmake"] = "# %s" ft["conf"] = "# %s" ft["crystal"] = "# %s" ft["css"] = "/* %s */" ft["d"] = "// %s" ft["dart"] = "// %s" ft["dockerfile"] = "# %s" ft["elm"] = "-- %s" ft["fish"] = "# %s" ft["gdscript"] = "# %s" ft["glsl"] = "// %s" ft["go"] = "// %s" ft["haskell"] = "-- %s" ft["html"] = "" ft["ini"] = "; %s" ft["java"] = "// %s" ft["javascript"] = "// %s" ft["jinja2"] = "{# %s #}" ft["json"] = "// %s" ft["julia"] = "# %s" ft["kotlin"] = "// %s" ft["lua"] = "-- %s" ft["markdown"] = "" ft["nginx"] = "# %s" ft["nim"] = "# %s" ft["objc"] = "// %s" ft["ocaml"] = "(* %s *)" ft["pascal"] = "{ %s }" ft["perl"] = "# %s" ft["php"] = "// %s" ft["pony"] = "// %s" ft["powershell"] = "# %s" ft["proto"] = "// %s" ft["python"] = "# %s" ft["python3"] = "# %s" ft["ruby"] = "# %s" ft["rust"] = "// %s" ft["scala"] = "// %s" ft["shell"] = "# %s" ft["sql"] = "-- %s" ft["swift"] = "// %s" ft["tex"] = "% %s" ft["toml"] = "# %s" ft["twig"] = "{# %s #}" ft["typescript"] = "// %s" ft["v"] = "// %s" ft["xml"] = "" ft["yaml"] = "# %s" ft["zig"] = "// %s" ft["zscript"] = "// %s" ft["zsh"] = "# %s" function updateCommentType(buf) -- NOTE: Using DoSetOptionNative to avoid LocalSettings[option] = true -- so that "comment.type" can be reset by a "filetype" change to default. if (buf.Settings["comment.type"] == "") then -- NOTE: This won't get triggered if a filetype is change via `setlocal filetype` -- since it is not registered with `RegisterGlobalOption()`` if buf.Settings["commenttype"] ~= nil then buf:DoSetOptionNative("comment.type", buf.Settings["commenttype"]) else if (ft[buf.Settings["filetype"]] ~= nil) then buf:DoSetOptionNative("comment.type", ft[buf.Settings["filetype"]]) else buf:DoSetOptionNative("comment.type", "# %s") end end end end function isCommented(bp, lineN, commentRegex) local line = bp.Buf:Line(lineN) local regex = commentRegex:gsub("%s+", "%s*") if string.match(line, regex) then return true end return false end function commentLine(bp, lineN, indentLen) updateCommentType(bp.Buf) local line = bp.Buf:Line(lineN) local commentType = bp.Buf.Settings["comment.type"] local sel = -bp.Cursor.CurSelection local curpos = -bp.Cursor.Loc local index = string.find(commentType, "%%s") - 1 local indent = string.sub(line, 1, indentLen) local trimmedLine = string.sub(line, indentLen + 1) trimmedLine = trimmedLine:gsub("%%", "%%%%") local commentedLine = commentType:gsub("%%s", trimmedLine) bp.Buf:Replace(buffer.Loc(0, lineN), buffer.Loc(#line, lineN), indent .. commentedLine) if bp.Cursor:HasSelection() then bp.Cursor.CurSelection[1].Y = sel[1].Y bp.Cursor.CurSelection[2].Y = sel[2].Y bp.Cursor.CurSelection[1].X = sel[1].X bp.Cursor.CurSelection[2].X = sel[2].X else bp.Cursor.X = curpos.X + index bp.Cursor.Y = curpos.Y end bp.Cursor:Relocate() bp.Cursor:StoreVisualX() end function uncommentLine(bp, lineN, commentRegex) updateCommentType(bp.Buf) local line = bp.Buf:Line(lineN) local commentType = bp.Buf.Settings["comment.type"] local sel = -bp.Cursor.CurSelection local curpos = -bp.Cursor.Loc local index = string.find(commentType, "%%s") - 1 if not string.match(line, commentRegex) then commentRegex = commentRegex:gsub("%s+", "%s*") end if string.match(line, commentRegex) then uncommentedLine = string.match(line, commentRegex) bp.Buf:Replace(buffer.Loc(0, lineN), buffer.Loc(#line, lineN), util.GetLeadingWhitespace(line) .. uncommentedLine) if bp.Cursor:HasSelection() then bp.Cursor.CurSelection[1].Y = sel[1].Y bp.Cursor.CurSelection[2].Y = sel[2].Y bp.Cursor.CurSelection[1].X = sel[1].X bp.Cursor.CurSelection[2].X = sel[2].X else bp.Cursor.X = curpos.X - index bp.Cursor.Y = curpos.Y end end bp.Cursor:Relocate() bp.Cursor:StoreVisualX() end function toggleCommentLine(bp, lineN, commentRegex) if isCommented(bp, lineN, commentRegex) then uncommentLine(bp, lineN, commentRegex) else commentLine(bp, lineN, #util.GetLeadingWhitespace(bp.Buf:Line(lineN))) end end function toggleCommentSelection(bp, startLine, endLine, commentRegex) local allComments = true for line = startLine, endLine do if not isCommented(bp, line, commentRegex) then allComments = false break end end -- NOTE: we assume that the indentation is either tabs only or spaces only local indentMin = -1 if not allComments then for line = startLine, endLine do local indentLen = #util.GetLeadingWhitespace(bp.Buf:Line(line)) if indentMin == -1 or indentLen < indentMin then indentMin = indentLen end end end for line = startLine, endLine do if allComments then uncommentLine(bp, line, commentRegex) else commentLine(bp, line, indentMin) end end end function comment(bp, args) updateCommentType(bp.Buf) local commentType = bp.Buf.Settings["comment.type"] local commentRegex = "^%s*" .. commentType:gsub("%%","%%%%"):gsub("%$","%$"):gsub("%)","%)"):gsub("%(","%("):gsub("%?","%?"):gsub("%*", "%*"):gsub("%-", "%-"):gsub("%.", "%."):gsub("%+", "%+"):gsub("%]", "%]"):gsub("%[", "%["):gsub("%%%%s", "(.*)") if bp.Cursor:HasSelection() then if bp.Cursor.CurSelection[1]:GreaterThan(-bp.Cursor.CurSelection[2]) then local endLine = bp.Cursor.CurSelection[1].Y if bp.Cursor.CurSelection[1].X == 0 then endLine = endLine - 1 end toggleCommentSelection(bp, bp.Cursor.CurSelection[2].Y, endLine, commentRegex) else local endLine = bp.Cursor.CurSelection[2].Y if bp.Cursor.CurSelection[2].X == 0 then endLine = endLine - 1 end toggleCommentSelection(bp, bp.Cursor.CurSelection[1].Y, endLine, commentRegex) end else toggleCommentLine(bp, bp.Cursor.Y, commentRegex) end end function string.starts(String,Start) return string.sub(String,1,string.len(Start))==Start end function preinit() config.RegisterCommonOption("comment", "type", "") end function init() config.MakeCommand("comment", comment, config.NoComplete) config.TryBindKey("Alt-/", "lua:comment.comment", false) config.TryBindKey("CtrlUnderscore", "lua:comment.comment", false) config.AddRuntimeFile("comment", config.RTHelp, "help/comment.md") end zyedidia-micro-6a62575/runtime/plugins/autoclose/0000775000175000017510000000000015125206537021405 5ustar nileshnileshzyedidia-micro-6a62575/runtime/plugins/autoclose/autoclose.lua0000664000175000017510000000470315125206537024112 0ustar nileshnileshVERSION = "1.0.0" local uutil = import("micro/util") local utf8 = import("utf8") local autoclosePairs = {"\"\"", "''", "``", "()", "{}", "[]"} local autoNewlinePairs = {"()", "{}", "[]"} function charAt(str, i) -- lua indexing is one off from go return uutil.RuneAt(str, i-1) end function onRune(bp, r) for i = 1, #autoclosePairs do if r == charAt(autoclosePairs[i], 2) then local curLine = bp.Buf:Line(bp.Cursor.Y) if charAt(curLine, bp.Cursor.X+1) == charAt(autoclosePairs[i], 2) then bp:Backspace() bp:CursorRight() break end if bp.Cursor.X > 1 and (uutil.IsWordChar(charAt(curLine, bp.Cursor.X-1)) or charAt(curLine, bp.Cursor.X-1) == charAt(autoclosePairs[i], 1)) then break end end if r == charAt(autoclosePairs[i], 1) then local curLine = bp.Buf:Line(bp.Cursor.Y) if bp.Cursor.X == uutil.CharacterCountInString(curLine) or not uutil.IsWordChar(charAt(curLine, bp.Cursor.X+1)) then -- the '-' here is to derefence the pointer to bp.Cursor.Loc which is automatically made -- when converting go structs to lua -- It needs to be dereferenced because the function expects a non pointer struct bp.Buf:Insert(-bp.Cursor.Loc, charAt(autoclosePairs[i], 2)) bp:CursorLeft() break end end end return true end function preInsertNewline(bp) local curLine = bp.Buf:Line(bp.Cursor.Y) local curRune = charAt(curLine, bp.Cursor.X) local nextRune = charAt(curLine, bp.Cursor.X+1) local ws = uutil.GetLeadingWhitespace(curLine) for i = 1, #autoNewlinePairs do if curRune == charAt(autoNewlinePairs[i], 1) then if nextRune == charAt(autoNewlinePairs[i], 2) then bp.Buf:Insert(-bp.Cursor.Loc, "\n" .. ws) bp:StartOfLine() bp:CursorLeft() bp:InsertNewline() bp:InsertTab() return false end end end return true end function preBackspace(bp) for i = 1, #autoclosePairs do local curLine = bp.Buf:Line(bp.Cursor.Y) if charAt(curLine, bp.Cursor.X+1) == charAt(autoclosePairs[i], 2) and charAt(curLine, bp.Cursor.X) == charAt(autoclosePairs[i], 1) then bp:Delete() end end return true end zyedidia-micro-6a62575/runtime/help/0000775000175000017510000000000015125206537016656 5ustar nileshnileshzyedidia-micro-6a62575/runtime/help/tutorial.md0000664000175000017510000000721515125206537021050 0ustar nileshnilesh# Tutorial This is a brief intro to micro's configuration system that will give some simple examples showing how to configure settings, rebind keys, and use `init.lua` to configure micro to your liking. Hopefully you'll find this useful. See `> help defaultkeys` for a list an explanation of the default keybindings. ### Settings In micro, your settings are stored in `~/.config/micro/settings.json`, a file that is created the first time you run micro. It is a json file which holds all the settings and their values. To change an option, you can either change the value in the `settings.json` file, or you can type it in directly while using micro. Press Ctrl-e to go to command mode, and type `set option value` (in the future, I will use `> set option value` to indicate pressing Ctrl-e). The change will take effect immediately and will also be saved to the `settings.json` file so that the setting will stick even after you close micro. You can also set options locally which means that the setting will only have the value you give it in the buffer you set it in. For example, if you have two splits open, and you type `> setlocal tabsize 2`, the tabsize will only be 2 in the current buffer. Also micro will not save this local change to the `settings.json` file. However, you can still set options locally in the `settings.json` file. For example, if you want the `tabsize` to be 2 only in Ruby files, and 4 otherwise, you could put the following in `settings.json`: ```json { "*.rb": { "tabsize": 2 }, "tabsize": 4 } ``` Micro will set the `tabsize` to 2 only in files which match the glob `*.rb`. If you would like to know more about all the available options, see the `options` topic (`> help options`). ### Keybindings Keybindings work in much the same way as options. You configure them using the `~/.config/micro/bindings.json` file. For example if you would like to bind `Ctrl-r` to redo you could put the following in `bindings.json`: ```json { "Ctrl-r": "Redo" } ``` Very simple. You can also bind keys while in micro by using the `> bind key action` command, but the bindings you make with the command won't be saved to the `bindings.json` file. For more information about keybindings, like which keys can be bound, and what actions are available, see the `keybindings` help topic (`> help keybindings`). ### Configuration with Lua If you need more power than the json files provide, you can use the `init.lua` file. Create it in `~/.config/micro`. This file is a lua file that is run when micro starts and is essentially a one-file plugin. The plugin name is `initlua`. This example will show you how to use the `init.lua` file by creating a binding to `Ctrl-r` which will execute the bash command `go run` on the current file, given that the current file is a Go file. You can do that by putting the following in `init.lua`: ```lua local config = import("micro/config") local shell = import("micro/shell") function init() -- true means overwrite any existing binding to Ctrl-r -- this will modify the bindings.json file config.TryBindKey("Ctrl-r", "lua:initlua.gorun", true) end function gorun(bp) local buf = bp.Buf if buf:FileType() == "go" then -- the true means run in the foreground -- the false means send output to stdout (instead of returning it) shell.RunInteractiveShell("go run " .. buf.Path, true, false) end end ``` Alternatively, you could get rid of the `TryBindKey` line, and put this line in the `bindings.json` file: ```json { "Ctrl-r": "lua:initlua.gorun" } ``` For more information about plugins and the lua system that micro uses, see the `plugins` help topic (`> help plugins`). zyedidia-micro-6a62575/runtime/help/plugins.md0000664000175000017510000005413215125206537020666 0ustar nileshnilesh# Plugins This help topic is about creating plugins. If you need help installing or managing plugins, look for `plugin` commands in `help commands`. If you want to enable or disable a plugin, look for `Plugin options` in `help options`. Micro supports creating plugins with a simple Lua system. Plugins are folders containing Lua files and possibly other source files placed in `~/.config/micro/plug`. The plugin directory (within `plug`) should contain at least one Lua file and a `repo.json` file. The `repo.json` file provides additional information such as the name of the plugin, the plugin's website, dependencies, etc. [Here is an example `repo.json` file](https://github.com/micro-editor/updated-plugins/blob/master/go-plugin/repo.json) from the go plugin, which has the following file structure: ``` ~/.config/micro/plug/go-plugin/ go.lua repo.json help/ go-plugin.md ``` The `go.lua` file contains the main code for the plugin, though the code may be distributed across multiple Lua files. The `repo.json` file contains information about the plugin, such as the website, description, version, and any requirements. Plugins may also have additional files that can be added to micro's runtime files, of which there are 5 types: * Colorschemes * Syntax files * Help files * Plugin files * Syntax header files In most cases, a plugin will want to add help files, but in certain cases a plugin may also want to add colorschemes or syntax files. No directory structure is enforced, but keeping runtime files in their own directories is good practice. ## Lua callbacks Plugins use Lua but also have access to many functions, both from micro and from the Go standard library. Plugins can also define functions that micro will call when certain events happen. Here is the list of callbacks that micro defines: * `init()`: this function should be used for your plugin initialization. This function is called after buffers have been initialized. * `preinit()`: initialization function called before buffers have been initialized. * `postinit()`: initialization function called after the `init()` function of all plugins has been called. * `deinit()`: cleanup function called when your plugin is unloaded or reloaded. * `onBufferOpen(buf)`: runs when a buffer is opened. The input contains the buffer object. * `onBufferOptionChanged(buf, option, old, new)`: runs when an option of the buffer has changed. The input contains the buffer object, the option name, the old and the new value. * `onBufPaneOpen(bufpane)`: runs when a bufpane is opened. The input contains the bufpane object. * `onSetActive(bufpane)`: runs when changing the currently active bufpane. * `onAction(bufpane)`: runs when `Action` is triggered by the user, where `Action` is a bindable action (see `> help keybindings`). A bufpane is passed as input. The function should return a boolean defining whether the action was successful, which is used when the action is chained with other actions (see `> help keybindings`) to determine whether the next actions in the chain should be executed or not. If the action is a mouse action, e.g. `MousePress`, the mouse event info is passed to the callback as an extra argument of type `*tcell.EventMouse`. See https://pkg.go.dev/github.com/micro-editor/tcell/v2#EventMouse for the description of this type and its methods. * `preAction(bufpane)`: runs immediately before `Action` is triggered by the user. Returns a boolean which defines whether the action should be canceled. Similarly to `onAction`, if the action is a mouse action, the mouse event info is passed to the callback as an extra argument of type `*tcell.EventMouse`. * `onRune(bufpane, rune)`: runs when the composed rune has been inserted * `preRune(bufpane, rune)`: runs before the composed rune will be inserted * `onAnyEvent()`: runs when literally anything happens. It is useful for detecting various changes of micro's state that cannot be detected using other callbacks. For example, a function that is run every time the user saves the buffer would be: ```lua function onSave(bp) ... return false end ``` The `bp` variable is a reference to the bufpane the action is being executed within. This is almost always the current bufpane. All available actions are listed in the keybindings section of the help. ## Accessing micro functions Some of micro's internal information is exposed in the form of packages, which can be imported by Lua plugins. A package can be imported in Lua, and a value within it can be accessed using the following syntax: ```lua local micro = import("micro") micro.Log("Hello") ``` The packages and their contents are listed below (in Go type signatures): * `micro` - `TermMessage(msg any...)`: temporarily close micro and print a message - `TermError(filename string, lineNum int, err string)`: temporarily close micro and print an error formatted as `filename, lineNum: err`. - `InfoBar() *InfoPane`: return the infobar BufPane object. - `Log(msg any...)`: write a message to `log.txt` (requires `-debug` flag, or binary built with `build-dbg`). - `SetStatusInfoFn(fn string)`: register the given lua function as accessible from the statusline formatting options. - `CurPane() *BufPane`: returns the current BufPane, or nil if the current pane is not a BufPane. - `CurTab() *Tab`: returns the current tab. - `Tabs() *TabList`: returns the global tab list. - `After(t time.Duration, f func())`: run function `f` in the background after time `t` elapses. See https://pkg.go.dev/time#Duration for the usage of `time.Duration`. Relevant links: [Time](https://pkg.go.dev/time#Duration) [BufPane](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/action#BufPane) [InfoPane](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/action#InfoPane) [Tab](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/action#Tab) [TabList](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/action#TabList) * `micro/config` - `MakeCommand(name string, action func(bp *BufPane, args[]string), completer buffer.Completer)`: create a command with the given name, and lua callback function when the command is run. A completer may also be given to specify how autocompletion should work with the custom command. Any lua function that takes a Buffer argument and returns a pair of string arrays is a valid completer, as are the built in completers below: - `FileComplete`: autocomplete using files in the current directory - `HelpComplete`: autocomplete using names of help documents - `OptionComplete`: autocomplete using names of options - `OptionValueComplete`: autocomplete using names of options, and valid values afterwards - `NoComplete`: no autocompletion suggestions - `TryBindKey(k, v string, overwrite bool) (bool, error)`: bind the key `k` to the string `v`. If `overwrite` is true, this will overwrite any existing binding to key `k`. Returns true if the binding was made, and a possible error. This operation can be rejected by `lockbindings` to prevent undesired actions by the user. - `Reload()`: reload configuration files. - `AddRuntimeFileFromMemory(filetype RTFiletype, filename, data string)`: add a runtime file to the `filetype` runtime filetype, with name `filename` and data `data`. - `AddRuntimeFilesFromDirectory(plugin string, filetype RTFiletype, directory, pattern string)`: add runtime files for the given plugin with the given RTFiletype from a directory within the plugin root. Only adds files that match the pattern using Go's `filepath.Match` - `AddRuntimeFile(plugin string, filetype RTFiletype, filepath string)`: add a given file inside the plugin root directory as a runtime file to the given RTFiletype category. - `ListRuntimeFiles(fileType RTFiletype) []string`: returns a list of names of runtime files of the given type. - `ReadRuntimeFile(fileType RTFiletype, name string) string`: returns the contents of a given runtime file. - `NewRTFiletype() int`: creates a new RTFiletype, and returns its value. - `RTColorscheme`: runtime files for colorschemes. - `RTSyntax`: runtime files for syntax files. - `RTHelp`: runtime files for help documents. - `RTPlugin`: runtime files for plugin source code. - `RegisterCommonOption(pl string, name string, defaultvalue any)`: registers a new option for the given plugin. The name of the option will be `pl.name`, and will have the given default value. Since this registers a common option, the option will be modifiable on a per-buffer basis, while also having a global value (in the GlobalSettings map). - `RegisterGlobalOption(pl string, name string, defaultvalue any)`: same as `RegisterCommonOption`, but the option cannot be modified locally to each buffer. - `GetGlobalOption(name string) any`: returns the value of a given plugin in the `GlobalSettings` map. - `SetGlobalOption(option, value string) error`: sets an option to a given value. This will try to convert the value into the proper type for the option. Can return an error if the option name is not valid, or the value can not be converted. - `SetGlobalOptionNative(option string, value any) error`: sets an option to a given value, where the type of value is the actual type of the value internally. Can return an error if the provided value is not valid for the given option. - `ConfigDir`: the path to micro's currently active config directory. Relevant links: [Buffer](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/buffer#Buffer) [buffer.Completer](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/buffer#Completer) [Error](https://pkg.go.dev/builtin#error) [filepath.Match](https://pkg.go.dev/path/filepath#Match) * `micro/shell` - `ExecCommand(name string, arg ...string) (string, error)`: runs an executable with the given arguments, and pipes the output (stderr and stdout) of the executable to an internal buffer, which is returned as a string, along with a possible error. - `RunCommand(input string) (string, error)`: same as `ExecCommand`, except this uses micro's argument parser to parse the arguments from the input. For example, `cat 'hello world.txt' file.txt`, will pass two arguments in the `ExecCommand` argument list (quoting arguments will preserve spaces). - `RunBackgroundShell(input string) (func() string, error)`: returns a function that will run the given shell command and return its output. - `RunInteractiveShell(input string, wait bool, getOutput bool) (string, error)`: temporarily closes micro and runs the given command in the terminal. If `wait` is true, micro will wait for the user to press enter before returning to text editing. If `getOutput` is true, micro will redirect stdout from the command to the returned string. - `JobStart(cmd string, onStdout, onStderr, onExit func(string, []any), userargs ...any) *exec.Cmd`: Starts a background job by running the shell on the given command (using `sh -c`). Three callbacks can be provided which will be called when the command generates stdout, stderr, or exits. The userargs will be passed to the callbacks, along with the output as the first argument of the callback. Returns the started command. - `JobSpawn(cmd string, cmdArgs []string, onStdout, onStderr, onExit func(string, []any), userargs ...any) *exec.Cmd`: same as `JobStart`, except doesn't run the command through the shell and instead takes as inputs the list of arguments. Returns the started command. - `JobStop(cmd *exec.Cmd)`: kills a job. - `JobSend(cmd *exec.Cmd, data string)`: sends some data to a job's stdin. - `RunTermEmulator(h *BufPane, input string, wait bool, getOutput bool, callback func(out string, userargs []any), userargs []any) error`: starts a terminal emulator from a given BufPane with the input command. If `wait` is true, it will wait for the user to exit by pressing enter once the executable has terminated, and if `getOutput` is true, it will redirect the stdout of the process to a pipe, which will be passed to the callback, which is a function that takes a string and a list of optional user arguments. This function returns an error on systems where the terminal emulator is not supported. - `TermEmuSupported`: true on systems where the terminal emulator is supported and false otherwise. Supported systems: * Linux * MacOS * Dragonfly * OpenBSD * FreeBSD Relevant links: [Cmd](https://pkg.go.dev/os/exec#Cmd) [BufPane](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/action#BufPane) [Error](https://pkg.go.dev/builtin#error) * `micro/buffer` - `NewMessage(owner string, msg string, start, end, Loc, kind MsgType) *Message`: creates a new message with an owner over a range defined by the start and end locations. - `NewMessageAtLine(owner string, msg string, line int, kindMsgType) *Message`: creates a new message with owner, type, and text at a given line. - `MTInfo`: info message. - `MTWarning`: warning message. - `MTError` error message. - `Loc(x, y int) Loc`: creates a new location struct. - `SLoc(line, row int) display.SLoc`: creates a new scrolling location struct. - `BTDefault`: default buffer type. - `BTHelp`: help buffer type. - `BTLog`: log buffer type. - `BTScratch`: scratch buffer type (cannot be saved). - `BTRaw`: raw buffer type. - `BTInfo`: info buffer type. - `NewBuffer(text, path string) *Buffer`: creates a new buffer with the given text at a certain path. - `NewBufferFromFile(path string) (*Buffer, error)`: creates a new buffer by reading the file at the given path from disk. Returns an error if the read operation fails (for example, due to the file not existing). - `ByteOffset(pos Loc, buf *Buffer) int`: returns the byte index of the given position in a buffer. - `Log(s string)`: writes a string to the log buffer. - `LogBuf() *Buffer`: returns the log buffer. Relevant links: [Message](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/buffer#Message) [Loc](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/buffer#Loc) [display.SLoc](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/display#SLoc) [Buffer](https://pkg.go.dev/github.com/zyedidia/micro/v2/internal/buffer#Buffer) [Error](https://pkg.go.dev/builtin#error) * `micro/util` - `RuneAt(str string, idx int) string`: returns the utf8 rune at a given index within a string. - `GetLeadingWhitespace(s string) string`: returns the leading whitespace of a string. - `IsWordChar(s string) bool`: returns true if the first rune in a string is a word character. - `String(b []byte) string`: converts a byte array to a string. - `Unzip(src, dest string) error`: unzips a file to given folder. - `Version`: micro's version number or commit hash - `SemVersion`: micro's semantic version - `HttpRequest(method string, url string, headers []string) (http.Response, error)`: makes a http request. - `CharacterCountInString(str string) int`: returns the number of characters in a string - `RuneStr(r rune) string`: converts a rune to a string. Relevant links: [Rune](https://pkg.go.dev/builtin#rune) This may seem like a small list of available functions, but some of the objects returned by the functions have many methods. The Lua plugin may access any public methods of an object returned by any of the functions above. Unfortunately, it is not possible to list all the available functions on this page. Please go to the internal documentation at https://pkg.go.dev/github.com/zyedidia/micro/v2/internal to see the full list of available methods. Note that only methods of types that are available to plugins via the functions above can be called from a plugin. For an even more detailed reference, see the source code on Github. For example, with a BufPane object called `bp`, you could call the `Save` function in Lua with `bp:Save()`. Note that Lua uses the `:` syntax to call a function rather than Go's `.` syntax. ```go micro.InfoBar().Message() ``` turns to ```lua micro.InfoBar():Message() ``` ## Accessing the Go standard library It is possible for your lua code to access many of the functions in the Go standard library. Simply import the package you'd like, and then you can use it. For example: ```lua local ioutil = import("io/ioutil") local fmt = import("fmt") local micro = import("micro") local data, err = ioutil.ReadFile("SomeFile.txt") if err ~= nil then micro.InfoBar():Error("Error reading file: SomeFile.txt") else -- Data is returned as an array of bytes -- Using Sprintf will convert it to a string local str = fmt.Sprintf("%s", data) -- Do something with the file you just read! -- ... end ``` Here are the packages from the Go standard library that you can access. Nearly all functions from these packages are supported. For an exact list of functions that are supported, you can look through `lua.go` (which should be easy to understand). * [fmt](https://pkg.go.dev/fmt) * [io](https://pkg.go.dev/io) * [io/ioutil](https://pkg.go.dev/io/ioutil) * [net](https://pkg.go.dev/net) * [math](https://pkg.go.dev/math) * [math/rand](https://pkg.go.dev/math/rand) * [os](https://pkg.go.dev/os) * [runtime](https://pkg.go.dev/runtime) * [path](https://pkg.go.dev/path) * [filepath](https://pkg.go.dev/filepath) * [strings](https://pkg.go.dev/strings) * [regexp](https://pkg.go.dev/regexp) * [errors](https://pkg.go.dev/errors) * [time](https://pkg.go.dev/time) * [unicode/utf8](https://pkg.go.dev/unicode/utf8) * [archive/zip](https://pkg.go.dev/archive/zip) * [net/http](https://pkg.go.dev/net/http) The following functions from the go-humanize package are also available: * `humanize`: - `Bytes(s uint64) string`: produces a human readable representation of an SI size. - `Ordinal(x int) string`: gives you the input number in a rank/ordinal format. [The Lua standard library](https://www.lua.org/manual/5.1/manual.html#5) is also available to plugins, though it is rather small. ## Adding help files, syntax files, or colorschemes in your plugin You can use the `AddRuntimeFile(name string, type config.RTFiletype, path string)` function to add various kinds of files to your plugin. For example, if you'd like to add a help topic to your plugin called `test`, you would create a `test.md` file and call the function: ```lua config = import("micro/config") config.AddRuntimeFile("test", config.RTHelp, "test.md") ``` Use `AddRuntimeFilesFromDirectory(name, type, dir, pattern)` to add a number of files to the runtime. To read the content of a runtime file, use `ReadRuntimeFile(fileType, name string)` or `ListRuntimeFiles(fileType string)` for all runtime files. In addition, there is `AddRuntimeFileFromMemory` which adds a runtime file based on a string that may have been constructed at runtime. ## Default plugins The following plugins come pre-installed with micro: * `autoclose`: automatically closes brackets, quotes, etc... * `comment`: provides automatic commenting for a number of languages * `ftoptions`: alters some default options (notably indentation) depending on the filetype * `linter`: provides extensible linting for many languages * `literate`: provides advanced syntax highlighting for the Literate programming tool. * `status`: provides some extensions to the status line (integration with Git and more). * `diff`: integrates the `diffgutter` option with Git. If you are in a Git directory, the diff gutter will show changes with respect to the most recent Git commit rather than the diff since opening the file. See `> help linter`, `> help comment`, and `> help status` for additional documentation specific to those plugins. These are good examples for many use-cases if you are looking to write your own plugins. ## Plugin Manager Micro also has a built in plugin manager, which you can invoke with the `> plugin ...` command, or in the shell with `micro -plugin ...`. For the valid commands you can use, see the `commands` help topic. The manager fetches plugins from the channels (which is simply a list of plugin metadata) which it knows about. By default, micro only knows about the [official channel](https://github.com/micro-editor/plugin-channel) but you can add your own third-party channels using the `pluginchannels` option and you can directly link third-party plugins to allow installation through the plugin manager with the `pluginrepos` option. If you'd like to publish a plugin you've made as an official plugin, you should upload your plugin online (preferably to Github) and add a `repo.json` file. This file will contain the metadata for your plugin. Here is an example: ```json [{ "Name": "pluginname", "Description": "Here is a nice concise description of my plugin", "Website": "https://github.com/user/plugin", "Tags": ["python", "linting"], "Versions": [ { "Version": "1.0.0", "Url": "https://github.com/user/plugin/archive/v1.0.0.zip", "Require": { "micro": ">=1.0.3" } } ] }] ``` Then open a pull request at the [official plugin channel](https://github.com/micro-editor/plugin-channel), adding a link to the raw `repo.json` that is in your plugin repository. To make updating the plugin work, the first line of your plugin's lua code should contain the version of the plugin. (Like this: `VERSION = "1.0.0"`) Please make sure to use [semver](https://semver.org/) for versioning. zyedidia-micro-6a62575/runtime/help/options.md0000664000175000017510000006346615125206537020712 0ustar nileshnilesh# Options Micro stores all of the user configuration in its configuration directory. Micro uses `$MICRO_CONFIG_HOME` as the configuration directory. If this environment variable is not set, it uses `$XDG_CONFIG_HOME/micro` instead. If that environment variable is not set, it uses `~/.config/micro` as the configuration directory. In the documentation, we use `~/.config/micro` to refer to the configuration directory (even if it may in fact be somewhere else if you have set either of the above environment variables). Here are the available options: * `autoindent`: when creating a new line, use the same indentation as the previous line. default value: `true` * `autosave`: automatically save the buffer every n seconds, where n is the value of the autosave option. Also when quitting on a modified buffer, micro will automatically save and quit. Be warned, this option saves the buffer without prompting the user, so data may be overwritten. If this option is set to `0`, no autosaving is performed. default value: `0` * `autosu`: When a file is saved that the user doesn't have permission to modify, micro will ask if the user would like to use super user privileges to save the file. If this option is enabled, micro will automatically attempt to use super user privileges to save without asking the user. default value: `false` * `backup`: micro will automatically keep backups of all open buffers. Backups are stored in `~/.config/micro/backups` and are removed when the buffer is closed cleanly. In the case of a system crash or a micro crash, the contents of the buffer can be recovered automatically by opening the file that was being edited before the crash, or manually by searching for the backup in the backup directory. Backups are made in the background for newly modified buffers every 8 seconds, or when micro detects a crash. default value: `true` * `backupdir`: the directory micro should place backups in. For the default value of `""` (empty string), the backup directory will be `ConfigDir/backups`, which is `~/.config/micro/backups` by default. The directory specified for backups will be created if it does not exist. default value: `""` (empty string) * `basename`: in the infobar and tabbar, show only the basename of the file being edited rather than the full path. default value: `false` * `clipboard`: specifies how micro should access the system clipboard. Possible values are: * `external`: accesses clipboard via an external tool, such as xclip/xsel or wl-clipboard on Linux, pbcopy/pbpaste on MacOS, and system calls on Windows. On Linux, if you do not have one of the tools installed, or if they are not working, micro will throw an error and use an internal clipboard. * `terminal`: accesses the clipboard via your terminal emulator. Note that there is limited support among terminal emulators for this feature (called OSC 52). Terminals that are known to work are Kitty (enable reading with `clipboard_control` setting), iTerm2 (only copying), st, rxvt-unicode and xterm if enabled (see `> help copypaste` for details). Note that Gnome-terminal does not support this feature. With this setting, copy-paste **will** work over ssh. See `> help copypaste` for details. * `internal`: micro will use an internal clipboard. default value: `external` * `colorcolumn`: if this is not set to 0, it will display a column at the specified column. This is useful if you want column 80 to be highlighted special for example. default value: `0` * `colorscheme`: use the given colorscheme. This setting is `global only`. The colorscheme can be either one of the colorschemes that micro comes with by default (such as `default`, `solarized` or `solarized-tc`) which are embedded in the micro binary, or a custom colorscheme stored in `~/.config/micro/colorschemes/$(option).micro` where `$(option)` is the option value. You can read more about micro's colorschemes and see the list of default colorschemes in `> help colors`. default value: `default` * `cursorline`: highlight the line that the cursor is on in a different color (the color is defined by the colorscheme you are using). default value: `true` * `detectlimit`: if this is not set to 0, it will limit the amount of first lines in a file that are matched to determine the filetype. A higher limit means better accuracy of guessing the filetype, but also taking more time. default value: `100` * `diffgutter`: display diff indicators before lines. default value: `false` * `divchars`: specifies the "divider" characters used for the dividing line between vertical/horizontal splits. The first character is for vertical dividers, and the second is for horizontal dividers. By default, for horizontal splits the statusline serves as a divider, but if the statusline is disabled the horizontal divider character will be used. default value: `|-` * `divreverse`: colorschemes provide the color (foreground and background) for the characters displayed in split dividers. With this option enabled, the colors specified by the colorscheme will be reversed (foreground and background colors swapped). default value: `true` * `encoding`: the encoding to open and save files with. Supported encodings are listed at https://www.w3.org/TR/encoding/. default value: `utf-8` * `eofnewline`: micro will automatically add a newline to the end of the file if one does not exist. default value: `true` * `fakecursor`: forces micro to render the cursor using terminal colors rather than the actual terminal cursor. This is useful when the terminal's cursor is slow or otherwise unavailable/undesirable to use. default value: `false` * `fastdirty`: this determines what kind of algorithm micro uses to determine if a buffer is modified or not. When `fastdirty` is on, micro just uses a boolean `modified` that is set to `true` as soon as the user makes an edit. This is fast, but can be inaccurate. If `fastdirty` is off, then micro will hash the current buffer against a hash of the original file (created when the buffer was loaded). This is more accurate but obviously more resource intensive. This option will be automatically enabled for the current buffer if the file size exceeds 50KB. default value: `false` * `fileformat`: this determines what kind of line endings micro will use for the file. Unix line endings are just `\n` (linefeed) whereas dos line endings are `\r\n` (carriage return + linefeed). The two possible values for this option are `unix` and `dos`. The fileformat will be automatically detected (when you open an existing file) and displayed on the statusline, but this option is useful if you would like to change the line endings or if you are starting a new file. Changing this option while editing a file will change its line endings. Opening a file with this option set will only have an effect if the file is empty/newly created, because otherwise the fileformat will be automatically detected from the existing line endings. default value: `unix` on Unix systems, `dos` on Windows * `filetype`: sets the filetype for the current buffer. Set this option to `off` to completely disable filetype detection. default value: `unknown`. This will be automatically overridden depending on the file you open. * `helpsplit`: sets the split type to be used by the `help` command. Possible values: * `vsplit`: open help in a vertical split pane * `hsplit`: open help in a horizontal split pane default value: `hsplit` * `hlsearch`: highlight all instances of the searched text after a successful search. This highlighting can be temporarily turned off via the `UnhighlightSearch` action (triggered by the Esc key by default) or toggled on/off via the `ToggleHighlightSearch` action. Note that these actions don't change the `hlsearch` setting. As long as `hlsearch` is set to true, the next search will have the highlighting turned on again. default value: `false` * `hltaberrors`: highlight tabs when spaces are expected, and spaces when tabs are expected. More precisely: if `tabstospaces` option is on, highlight all tab characters; if `tabstospaces` is off, highlight space characters in the initial indent part of the line. default value: `false` * `hltrailingws`: highlight trailing whitespaces at ends of lines. Note that it doesn't highlight newly added trailing whitespaces that naturally occur while typing text. It highlights only nasty forgotten trailing whitespaces. default value: `false` * `ignorecase`: perform case-insensitive searches. default value: `true` * `incsearch`: enable incremental search in "Find" prompt (matching as you type). default value: `true` * `indentchar`: sets the character to be shown to display tab characters. This option is **deprecated**, use the `tab` key in `showchars` option instead. default value: ` ` (space) * `infobar`: enables the line at the bottom of the editor where messages are printed. This option is `global only`. default value: `true` * `keepautoindent`: when using autoindent, whitespace is added for you. This option determines if when you move to the next line without any insertions the whitespace that was added should be deleted to remove trailing whitespace. By default, the autoindent whitespace is deleted if the line was left empty. default value: `false` * `keymenu`: display the nano-style key menu at the bottom of the screen. Note that ToggleKeyMenu is bound to `Alt-g` by default and this is displayed in the statusline. To disable the key binding, bind `Alt-g` to `None`. default value: `false` * `lockbindings`: prevent plugins and lua scripts from binding any keys. Any custom actions must be binded manually either via commands like `bind` or by modifying the `bindings.json` file. default value: `false` * `matchbrace`: show matching braces for '()', '{}', '[]' when the cursor is on a brace character or (if `matchbraceleft` is enabled) next to it. default value: `true` * `matchbraceleft`: simulate I-beam cursor behavior (cursor located not on a character but "between" characters): when showing matching braces, if there is no brace character directly under the cursor, match the brace character to the left of the cursor instead. Also when jumping to the matching brace, move the cursor either to the matching brace character or to the character next to it, depending on whether the initial cursor position was on the brace character or next to it (i.e. "inside" or "outside" the braces). With `matchbraceleft` disabled, micro will only match the brace directly under the cursor and will only jump to precisely to the matching brace. default value: `true` * `matchbracestyle`: whether to underline or highlight matching braces when `matchbrace` is enabled. The color of highlight is determined by the `match-brace` field in the current theme. Possible values: * `underline`: underline matching braces. * `highlight`: use `match-brace` style from the current theme. default value: `underline` * `mkparents`: if a file is opened on a path that does not exist, the file cannot be saved because the parent directories don't exist. This option lets micro automatically create the parent directories in such a situation. default value: `false` * `mouse`: mouse support. When mouse support is disabled, usually the terminal will be able to access mouse events which can be useful if you want to copy from the terminal instead of from micro (if over ssh for example, because the terminal has access to the local clipboard and micro does not). default value: `true` * `multiopen`: specifies how to layout multiple files opened at startup. Most useful as a command-line option, like `-multiopen vsplit`. Possible values correspond to commands (see `> help commands`) that open files: * `tab`: open each file in a separate tab. * `vsplit`: open files side-by-side. * `hsplit`: open files stacked top to bottom. default value: `tab` * `pageoverlap`: the number of lines from the current view to keep in view when paging up or down. If this is set to 2, for instance, and you page down, the last two lines of the previous page will be the first two lines of the next page. default value: `2` * `parsecursor`: if enabled, this will cause micro to parse filenames such as `file.txt:10:5` as requesting to open `file.txt` with the cursor at line 10 and column 5. The column number can also be dropped to open the file at a given line and column 0. Note that with this option enabled it is not possible to open a file such as `file.txt:10:5`, where `:10:5` is part of the filename. It is also possible to open a file with a certain cursor location by using the `+LINE:COL` flag syntax. See `micro -help` for the command line options. default value: `false` * `paste`: treat characters sent from the terminal in a single chunk as a paste event rather than a series of manual key presses. If you are pasting using the terminal keybinding (not `Ctrl-v`, which is micro's default paste keybinding) then it is a good idea to enable this option during the paste and disable once the paste is over. See `> help copypaste` for details about copying and pasting in a terminal environment. default value: `false` * `permbackup`: this option causes backups (see `backup` option) to be permanently saved. With permanent backups, micro will not remove backups when files are closed and will never apply them to existing files. Use this option if you are interested in manually managing your backup files. default value: `false` * `pluginchannels`: list of URLs pointing to plugin channels for downloading and installing plugins. A plugin channel consists of a json file with links to plugin repos, which store information about plugin versions and download URLs. By default, this option points to the official plugin channel hosted on GitHub at https://github.com/micro-editor/plugin-channel. default value: `https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json` * `pluginrepos`: a list of links to plugin repositories. default value: `` * `readonly`: when enabled, disallows edits to the buffer. It is recommended to only ever set this option locally using `setlocal`. default value: `false` * `relativeruler`: make line numbers display relatively. If set to true, all lines except for the line that the cursor is located will display the distance from the cursor's line. default value: `false` * `reload`: controls the reload behavior of the current buffer in case the file has changed. The available options are `prompt`, `auto` & `disabled`. default value: `prompt` * `rmtrailingws`: micro will automatically trim trailing whitespaces at ends of lines. Note: This setting overrides `keepautoindent` and isn't used at timed `autosave` or forced `autosave` in case the buffer didn't change. A manual save will involve the action regardless if the buffer has been changed or not. default value: `false` * `ruler`: display line numbers. default value: `true` * `savecursor`: remember where the cursor was last time the file was opened and put it there when you open the file again. Information is saved to `~/.config/micro/buffers/` default value: `false` * `savehistory`: remember command history between closing and re-opening micro. Information is saved to `~/.config/micro/buffers/history`. default value: `true` * `saveundo`: when this option is on, undo is saved even after you close a file so if you close and reopen a file, you can keep undoing. Information is saved to `~/.config/micro/buffers/`. default value: `false` * `scrollbar`: display a scroll bar default value: `false` * `scrollbarchar`: specifies the character used for displaying the scrollbar default value: `|` * `scrollmargin`: margin at which the view starts scrolling when the cursor approaches the edge of the view. default value: `3` * `scrollspeed`: amount of lines to scroll for one scroll event. default value: `2` * `showchars`: sets what characters to be shown to display various invisible characters in the file. The characters shown will not be inserted into files. This option is specified in the form of `key1=value1,key2=value2,...`. Here are the list of keys: - `space`: space characters - `tab`: tab characters. If set, overrides the `indentchar` option. - `ispace`: space characters at indent position before the first visible character in a line. If this is not set, `space` will be shown instead. - `itab`: tab characters before the first visible character in a line. If this is not set, `tab` will be shown instead. Only `tab` and `itab` can display multiple characters (if possible), otherwise only the first character will be displayed. An example of this option value could be `tab=>,space=.,itab=|>,ispace=|` The color of the shown character is determined by the `indent-char` field in the current theme rather than the default text color. default value: `` * `smartpaste`: add leading whitespace when pasting multiple lines. This will attempt to preserve the current indentation level when pasting an unindented block. default value: `true` * `softwrap`: wrap lines that are too long to fit on the screen. default value: `false` * `splitbottom`: when a horizontal split is created, create it below the current split. default value: `true` * `splitright`: when a vertical split is created, create it to the right of the current split. default value: `true` * `statusformatl`: format string definition for the left-justified part of the statusline. Special directives should be placed inside `$()`. Special directives include: `filename`, `modified`, `line`, `col`, `lines`, `percentage`, `opt`, `overwrite`, `bind`. The `opt` and `bind` directives take either an option or an action afterward and fill in the value of the option or the key bound to the action. default value: `$(filename) $(modified)$(overwrite)($(line),$(col)) $(status.paste)| ft:$(opt:filetype) | $(opt:fileformat) | $(opt:encoding)` * `statusformatr`: format string definition for the right-justified part of the statusline. default value: `$(bind:ToggleKeyMenu): bindings, $(bind:ToggleHelp): help` * `statusline`: display the status line at the bottom of the screen. default value: `true` * `sucmd`: specifies the super user command. On most systems this is "sudo" but on BSD it can be "doas." This option can be customized and is only used when saving with su. default value: `sudo` * `syntax`: enables syntax highlighting. default value: `true` * `tabhighlight`: inverts the tab characters' (filename, save indicator, etc) colors with respect to the tab bar. default value: `false` * `tabmovement`: navigate spaces at the beginning of lines as if they are tabs (e.g. move over 4 spaces at once). This option only does anything if `tabstospaces` is on. default value: `false` * `tabreverse`: reverses the tab bar colors when active. default value: `true` * `tabsize`: the size in spaces that a tab character should be displayed with. default value: `4` * `tabstospaces`: use spaces instead of tabs. Note: This option will be overridden by [the `ftoptions` plugin](https://github.com/zyedidia/micro/blob/master/runtime/plugins/ftoptions/ftoptions.lua) for certain filetypes. To disable this behavior, add `"ftoptions": false` to your config. See [issue #2213](https://github.com/zyedidia/micro/issues/2213) for more details. default value: `false` * `truecolor`: controls whether micro will use true colors (24-bit colors) when using a colorscheme with true colors, such as `solarized-tc` or `atom-dark`. * `auto`: enable usage of true color if micro detects that it is supported by the terminal, otherwise disable it. * `on`: force usage of true color even if micro does not detect its support by the terminal (of course this is not guaranteed to work well unless the terminal actually supports true color). * `off`: disable true color usage. Note: The change will take effect after the next start of `micro`. default value: `auto` * `useprimary` (only useful on unix): defines whether or not micro will use the primary clipboard to copy selections in the background. This does not affect the normal clipboard using `Ctrl-c` and `Ctrl-v`. default value: `true` * `wordwrap`: wrap long lines by words, i.e. break at spaces. This option only does anything if `softwrap` is on. default value: `false` * `xterm`: micro will assume that the terminal it is running in conforms to `xterm-256color` regardless of what the `$TERM` variable actually contains. Enabling this option may cause unwanted effects if your terminal in fact does not conform to the `xterm-256color` standard. default value: `false` --- Plugin options: all plugins come with a special option to enable or disable them. The option is a boolean with the same name as the plugin itself. By default, the following plugins are provided, each with an option to enable or disable them: * `autoclose`: automatically closes brackets, quotes, etc... * `comment`: provides automatic commenting for a number of languages * `ftoptions`: alters some default options depending on the filetype * `linter`: provides extensible linting for many languages * `literate`: provides advanced syntax highlighting for the Literate programming tool. * `status`: provides some extensions to the status line (integration with Git and more). * `diff`: integrates the `diffgutter` option with Git. If you are in a Git directory, the diff gutter will show changes with respect to the most recent Git commit rather than the diff since opening the file. Any option you set in the editor will be saved to the file `~/.config/micro/settings.json` so, in effect, your configuration file will be created for you. If you'd like to take your configuration with you to another machine, simply copy the `settings.json` to the other machine. ## Settings.json file The `settings.json` file should go in your configuration directory (by default at `~/.config/micro`), and should contain only options which have been modified from their default setting. Here is the full list of options in json format, so that you can see what the formatting should look like. ```json { "autoclose": true, "autoindent": true, "autosave": 0, "autosu": false, "backup": true, "backupdir": "", "basename": false, "clipboard": "external", "colorcolumn": 0, "colorscheme": "default", "comment": true, "cursorline": true, "detectlimit": 100, "diff": true, "diffgutter": false, "divchars": "|-", "divreverse": true, "encoding": "utf-8", "eofnewline": true, "fakecursor": false, "fastdirty": false, "fileformat": "unix", "filetype": "unknown", "ftoptions": true, "helpsplit": "hsplit", "hlsearch": false, "hltaberrors": false, "hltrailingws": false, "ignorecase": true, "incsearch": true, "indentchar": " ", "infobar": true, "initlua": true, "keepautoindent": false, "keymenu": false, "linter": true, "literate": true, "matchbrace": true, "matchbraceleft": true, "matchbracestyle": "underline", "mkparents": false, "mouse": true, "multiopen": "tab", "pageoverlap": 2, "parsecursor": false, "paste": false, "permbackup": false, "pluginchannels": [ "https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json" ], "pluginrepos": [], "readonly": false, "relativeruler": false, "reload": "prompt", "rmtrailingws": false, "ruler": true, "savecursor": false, "savehistory": true, "saveundo": false, "scrollbar": false, "scrollbarchar": "|", "scrollmargin": 3, "scrollspeed": 2, "showchars": "", "smartpaste": true, "softwrap": false, "splitbottom": true, "splitright": true, "status": true, "statusformatl": "$(filename) $(modified)$(overwrite)($(line),$(col)) $(status.paste)| ft:$(opt:filetype) | $(opt:fileformat) | $(opt:encoding)", "statusformatr": "$(bind:ToggleKeyMenu): bindings, $(bind:ToggleHelp): help", "statusline": true, "sucmd": "sudo", "syntax": true, "tabhighlight": true, "tabmovement": false, "tabreverse": false, "tabsize": 4, "tabstospaces": false, "useprimary": true, "wordwrap": false, "xterm": false } ``` ## Global and local settings You can set these settings either globally or locally. Locally means that the setting won't be saved to `~/.config/micro/settings.json` and that it will only be set in the current buffer. Setting an option globally is the default, and will set the option in all buffers. Use the `setlocal` command to set an option locally rather than globally. The `colorscheme` option is global only, and the `filetype` option is local only. To set an option locally, use `setlocal` instead of `set`. In the `settings.json` file you can also put set options locally by specifying either a glob or a filetype. Here is an example which has `tabstospaces` on for all files except Go files, and `tabsize` 4 for all files except Ruby files: ```json { "ft:go": { "tabstospaces": false }, "ft:ruby": { "tabsize": 2 }, "tabstospaces": true, "tabsize": 4 } ``` Or similarly you can match with globs: ```json { "*.go": { "tabstospaces": false }, "*.rb": { "tabsize": 2 }, "tabstospaces": true, "tabsize": 4 } ``` zyedidia-micro-6a62575/runtime/help/keybindings.md0000664000175000017510000004642215125206537021516 0ustar nileshnilesh# Keybindings Micro has a plethora of hotkeys that make it easy and powerful to use and all hotkeys are fully customizable to your liking. Custom keybindings are stored internally in micro if changed with the `> bind` command or can also be added in the file `~/.config/micro/bindings.json` as discussed below. For a list of the default keybindings in the json format used by micro, please see the end of this file. For a more user-friendly list with explanations of what the default hotkeys are and what they do, please see `> help defaultkeys` (a json formatted list of default keys is included at the end of this document). If `~/.config/micro/bindings.json` does not exist, you can simply create it. Micro will know what to do with it. You can use Ctrl + arrows to move word by word (Alt + arrows for Mac). Alt + left and right move the cursor to the start and end of the line (Ctrl + left/right for Mac), and Ctrl + up and down move the cursor to the start and end of the buffer. You can hold shift with all of these movement actions to select while moving. ## Rebinding keys The bindings may be rebound using the `~/.config/micro/bindings.json` file. Each key is bound to an action. For example, to bind `Ctrl-y` to undo and `Ctrl-z` to redo, you could put the following in the `bindings.json` file. ```json { "Ctrl-y": "Undo", "Ctrl-z": "Redo" } ``` **Note:** The syntax `` is equivalent to `-`. In addition, `Ctrl-Shift` bindings are not supported by terminals, and are the same as simply `Ctrl` bindings. This means that `CtrlG`, `Ctrl-G`, and `Ctrl-g` all mean the same thing. However, for `Alt` this is not the case: `AltG` and `Alt-G` mean `Alt-Shift-g`, while `Alt-g` does not require the Shift modifier. In addition to editing your `~/.config/micro/bindings.json`, you can run `>bind ` For a list of bindable actions, see below. You can also chain commands when rebinding. For example, if you want `Alt-s` to save and quit you can bind it like so: ```json { "Alt-s": "Save,Quit" } ``` Each action will return a success flag. Actions can be chained such that the chain only continues when there are successes, or failures, or either. The `,` separator will always chain to the next action. The `|` separator will abort the chain if the action preceding it succeeds, and the `&` will abort the chain if the action preceding it fails. For example, in the default bindings, tab is bound as ``` "Tab": "Autocomplete|IndentSelection|InsertTab" ``` This means that if the `Autocomplete` action is successful, the chain will abort. Otherwise, it will try `IndentSelection`, and if that fails too, it will execute `InsertTab`. To use `,`, `|` or `&` in an action (as an argument to a command, for example), escape it with `\` or wrap it in single or double quotes. If the action has an `onAction` lua callback, for example `onAutocomplete` (see `> help plugins`), then the action is only considered successful if the action itself succeeded *and* the callback returned true. If there are multiple `onAction` callbacks for this action, registered by multiple plugins, then the action is only considered successful if the action itself succeeded and all the callbacks returned true. ## Binding commands You can also bind a key to execute a command in command mode (see `help commands`). Simply prepend the binding with `command:`. For example: ```json { "Alt-p": "command:pwd" } ``` **Note for macOS**: By default, macOS terminals do not forward alt events and instead insert unicode characters. To fix this, do the following: * iTerm2: select `Esc+` for `Left Option Key` in `Preferences->Profiles->Keys`. * Terminal.app: Enable `Use Option key as Meta key` in `Preferences->Profiles->Keyboard`. Now when you press `Alt-p` the `pwd` command will be executed which will show your working directory in the infobar. You can also bind an "editable" command with `command-edit:`. This means that micro won't immediately execute the command when you press the binding, but instead just place the string in the infobar in command mode. For example, you could rebind `Ctrl-g` to `> help`: ```json { "Ctrl-g": "command-edit:help " } ``` Now when you press `Ctrl-g`, `help` will appear in the command bar and your cursor will be placed after it (note the space in the json that controls the cursor placement). ## Binding Lua functions You can also bind a key to a Lua function provided by a plugin, or by your own `~/.config/micro/init.lua`. For example: ```json { "Alt-q": "lua:foo.bar" } ``` where `foo` is the name of the plugin and `bar` is the name of the lua function in it, e.g.: ```lua local micro = import("micro") function bar(bp) micro.InfoBar():Message("Bar action triggered") return true end ``` See `> help plugins` for more informations on how to write lua functions. For `~/.config/micro/init.lua` the plugin name is `initlua` (so the keybinding in this example would be `"Alt-q": "lua:initlua.bar"`). The currently active bufpane is passed to the lua function as the argument. If the key is a mouse button, e.g. `MouseLeft` or `MouseWheelUp`, the mouse event info is passed to the lua function as the second argument, of type `*tcell.EventMouse`. See https://pkg.go.dev/github.com/micro-editor/tcell/v2#EventMouse for the description of this type and its methods. The return value of the lua function defines whether the action has succeeded. This is used when chaining lua functions with other actions. They can be chained the same way as regular actions as described above, for example: ``` "Alt-q": "lua:initlua.bar|Quit" ``` ## Binding raw escape sequences Only read this section if you are interested in binding keys that aren't on the list of supported keys for binding. One of the drawbacks of using a terminal-based editor is that the editor must get all of its information about key events through the terminal. The terminal sends these events in the form of escape sequences often (but not always) starting with `0x1b`. For example, if micro reads `\x1b[1;5D`, on most terminals this will mean the user pressed CtrlLeft. For many key chords though, the terminal won't send any escape code or will send an escape code already in use. For example for `CtrlBackspace`, my terminal sends `\u007f` (note this doesn't start with `0x1b`), which it also sends for `Backspace` meaning micro can't bind `CtrlBackspace`. However, some terminals do allow you to bind keys to send specific escape sequences you define. Then from micro you can directly bind those escape sequences to actions. For example, to bind `CtrlBackspace` you can instruct your terminal to send `\x1bctrlback` and then bind it in `bindings.json`: ```json { "\u001bctrlback": "DeleteWordLeft" } ``` Here are some instructions for sending raw escapes in different terminals ### iTerm2 In iTerm2, you can do this in `Preferences->Profiles->Keys` then click the `+`, input your keybinding, and for the `Action` select `Send Escape Sequence`. For the above example your would type `ctrlback` into the box (the `\x1b`) is automatically sent by iTerm2. ### Linux using loadkeys You can do this in linux using the loadkeys program. Coming soon! ## Unbinding keys It is also possible to disable any of the default key bindings by use of the `None` action in the user's `bindings.json` file. ## Bindable actions and bindable keys The list of default keybindings contains most of the possible actions and keys which you can use, but not all of them. Here is a full list of both. Full list of possible actions: ``` CursorUp CursorDown CursorPageUp CursorPageDown CursorLeft CursorRight CursorStart CursorEnd CursorToViewTop CursorToViewCenter CursorToViewBottom SelectToStart SelectToEnd SelectUp SelectDown SelectLeft SelectRight WordRight WordLeft SubWordRight SubWordLeft SelectWordRight SelectWordLeft SelectSubWordRight SelectSubWordLeft DeleteWordRight DeleteWordLeft DeleteSubWordRight DeleteSubWordLeft SelectLine SelectToStartOfLine SelectToStartOfText SelectToStartOfTextToggle SelectToEndOfLine ParagraphPrevious ParagraphNext SelectToParagraphPrevious SelectToParagraphNext InsertNewline Backspace Delete InsertTab Save SaveAll SaveAs Find FindLiteral FindNext FindPrevious DiffNext DiffPrevious Center Undo Redo Copy CopyLine Cut CutLine Duplicate DuplicateLine DeleteLine MoveLinesUp MoveLinesDown IndentSelection OutdentSelection Autocomplete CycleAutocompleteBack OutdentLine IndentLine Paste PastePrimary SelectAll OpenFile Start End PageUp PageDown SelectPageUp SelectPageDown HalfPageUp HalfPageDown StartOfText StartOfTextToggle StartOfLine EndOfLine ToggleHelp ToggleKeyMenu ToggleDiffGutter ToggleRuler ToggleHighlightSearch UnhighlightSearch ResetSearch ClearStatus ShellMode CommandMode ToggleOverwriteMode Escape Quit QuitAll ForceQuit AddTab PreviousTab NextTab FirstTab LastTab NextSplit PreviousSplit FirstSplit LastSplit Unsplit VSplit HSplit ToggleMacro PlayMacro Suspend (Unix only) ScrollUp ScrollDown SpawnMultiCursor SpawnMultiCursorUp SpawnMultiCursorDown SpawnMultiCursorSelect RemoveMultiCursor RemoveAllMultiCursors SkipMultiCursor SkipMultiCursorBack JumpToMatchingBrace JumpLine Deselect ClearInfo None ``` The `StartOfTextToggle` and `SelectToStartOfTextToggle` actions toggle between jumping to the start of the text (first) and start of the line. The `CutLine` action cuts the current line and adds it to the previously cut lines in the clipboard since the last paste (rather than just replaces the clipboard contents with this line). So you can cut multiple, not necessarily consecutive lines to the clipboard just by pressing `Ctrl-k` multiple times, without selecting them. If you want the more traditional behavior i.e. just rewrite the clipboard every time, you can use `CopyLine,DeleteLine` action instead of `CutLine`. You can also bind some mouse actions (these must be bound to mouse buttons) ``` MousePress MouseDrag MouseRelease MouseMultiCursor ``` Here is the list of all possible keys you can bind: ``` Up Down Right Left UpLeft UpRight DownLeft DownRight Center PageUp PageDown Home End Insert Delete Help Exit Clear Cancel Print Pause Backtab F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 F32 F33 F34 F35 F36 F37 F38 F39 F40 F41 F42 F43 F44 F45 F46 F47 F48 F49 F50 F51 F52 F53 F54 F55 F56 F57 F58 F59 F60 F61 F62 F63 F64 CtrlSpace Ctrl-a Ctrl-b Ctrl-c Ctrl-d Ctrl-e Ctrl-f Ctrl-g Ctrl-h Ctrl-i Ctrl-j Ctrl-k Ctrl-l Ctrl-m Ctrl-n Ctrl-o Ctrl-p Ctrl-q Ctrl-r Ctrl-s Ctrl-t Ctrl-u Ctrl-v Ctrl-w Ctrl-x Ctrl-y Ctrl-z CtrlLeftSq CtrlBackslash CtrlRightSq CtrlCarat CtrlUnderscore Backspace OldBackspace Tab Esc Escape Enter ``` You can also bind some mouse buttons (they may be bound to normal actions or mouse actions) ``` MouseLeft MouseLeftDrag MouseLeftRelease MouseMiddle MouseMiddleDrag MouseMiddleRelease MouseRight MouseRightDrag MouseRightRelease MouseWheelUp MouseWheelDown MouseWheelLeft MouseWheelRight ``` ## Key sequences Key sequences can be bound by specifying valid keys one after another in brackets, such as ``. # Default keybinding configuration. A select few keybindings are different on MacOS compared to other operating systems. This is because different OSes have different conventions for text editing defaults. ```json { "Up": "CursorUp", "Down": "CursorDown", "Right": "CursorRight", "Left": "CursorLeft", "ShiftUp": "SelectUp", "ShiftDown": "SelectDown", "ShiftLeft": "SelectLeft", "ShiftRight": "SelectRight", "AltLeft": "WordLeft", (Mac) "AltRight": "WordRight", (Mac) "AltUp": "MoveLinesUp", "AltDown": "MoveLinesDown", "CtrlShiftRight": "SelectWordRight", "CtrlShiftLeft": "SelectWordLeft", "AltLeft": "StartOfTextToggle", "AltRight": "EndOfLine", "AltShiftRight": "SelectWordRight", (Mac) "AltShiftLeft": "SelectWordLeft", (Mac) "CtrlLeft": "StartOfText", (Mac) "CtrlRight": "EndOfLine", (Mac) "AltShiftLeft": "SelectToStartOfTextToggle", "CtrlShiftLeft": "SelectToStartOfTextToggle", (Mac) "ShiftHome": "SelectToStartOfTextToggle", "AltShiftRight": "SelectToEndOfLine", "CtrlShiftRight": "SelectToEndOfLine", (Mac) "ShiftEnd": "SelectToEndOfLine", "CtrlUp": "CursorStart", "CtrlDown": "CursorEnd", "CtrlShiftUp": "SelectToStart", "CtrlShiftDown": "SelectToEnd", "Alt-{": "ParagraphPrevious", "Alt-}": "ParagraphNext", "Enter": "InsertNewline", "Ctrl-h": "Backspace", "Backspace": "Backspace", "Alt-CtrlH": "DeleteWordLeft", "Alt-Backspace": "DeleteWordLeft", "Tab": "Autocomplete|IndentSelection|InsertTab", "Backtab": "OutdentSelection|OutdentLine", "Ctrl-o": "OpenFile", "Ctrl-s": "Save", "Ctrl-f": "Find", "Alt-F": "FindLiteral", "Ctrl-n": "FindNext", "Ctrl-p": "FindPrevious", "Alt-[": "DiffPrevious|CursorStart", "Alt-]": "DiffNext|CursorEnd", "Ctrl-z": "Undo", "Ctrl-y": "Redo", "Ctrl-c": "Copy|CopyLine", "Ctrl-x": "Cut|CutLine", "Ctrl-k": "CutLine", "Ctrl-d": "Duplicate|DuplicateLine", "Ctrl-v": "Paste", "Ctrl-a": "SelectAll", "Ctrl-t": "AddTab", "Alt-,": "PreviousTab|LastTab", "Alt-.": "NextTab|FirstTab", "Home": "StartOfText", "End": "EndOfLine", "CtrlHome": "CursorStart", "CtrlEnd": "CursorEnd", "PageUp": "CursorPageUp", "PageDown": "CursorPageDown", "CtrlPageUp": "PreviousTab|LastTab", "CtrlPageDown": "NextTab|FirstTab", "ShiftPageUp": "SelectPageUp", "ShiftPageDown": "SelectPageDown", "Ctrl-g": "ToggleHelp", "Alt-g": "ToggleKeyMenu", "Ctrl-r": "ToggleRuler", "Ctrl-l": "command-edit:goto ", "Delete": "Delete", "Ctrl-b": "ShellMode", "Ctrl-q": "Quit", "Ctrl-e": "CommandMode", "Ctrl-w": "NextSplit|FirstSplit", "Ctrl-u": "ToggleMacro", "Ctrl-j": "PlayMacro", "Insert": "ToggleOverwriteMode", // Emacs-style keybindings "Alt-f": "WordRight", "Alt-b": "WordLeft", "Alt-a": "StartOfLine", "Alt-e": "EndOfLine", // Integration with file managers "F2": "Save", "F3": "Find", "F4": "Quit", "F7": "Find", "F10": "Quit", "Esc": "Escape", // Mouse bindings "MouseWheelUp": "ScrollUp", "MouseWheelDown": "ScrollDown", "MouseLeft": "MousePress", "MouseLeftDrag": "MouseDrag", "MouseLeftRelease": "MouseRelease", "MouseMiddle": "PastePrimary", "Ctrl-MouseLeft": "MouseMultiCursor", // Multi-cursor bindings "Alt-n": "SpawnMultiCursor", "AltShiftUp": "SpawnMultiCursorUp", "AltShiftDown": "SpawnMultiCursorDown", "Alt-m": "SpawnMultiCursorSelect", "Alt-p": "RemoveMultiCursor", "Alt-c": "RemoveAllMultiCursors", "Alt-x": "SkipMultiCursor", } ``` ## Pane type bindings Keybindings can be specified for different pane types as well. For example, to make a binding that only affects the command bar, use the `command` subgroup: ``` { "command": { "Ctrl-w": "WordLeft" } } ``` The possible pane types are `buffer` (normal buffer), `command` (command bar), and `terminal` (terminal pane). The defaults for the command and terminal panes are given below: ``` { "terminal": { "": "Exit", "": "CommandMode", "": "NextSplit" }, "command": { "Up": "HistoryUp", "Down": "HistoryDown", "Right": "CursorRight", "Left": "CursorLeft", "ShiftUp": "SelectUp", "ShiftDown": "SelectDown", "ShiftLeft": "SelectLeft", "ShiftRight": "SelectRight", "AltLeft": "StartOfTextToggle", "AltRight": "EndOfLine", "AltUp": "CursorStart", "AltDown": "CursorEnd", "AltShiftRight": "SelectWordRight", "AltShiftLeft": "SelectWordLeft", "CtrlLeft": "WordLeft", "CtrlRight": "WordRight", "CtrlShiftLeft": "SelectToStartOfTextToggle", "ShiftHome": "SelectToStartOfTextToggle", "CtrlShiftRight": "SelectToEndOfLine", "ShiftEnd": "SelectToEndOfLine", "CtrlUp": "CursorStart", "CtrlDown": "CursorEnd", "CtrlShiftUp": "SelectToStart", "CtrlShiftDown": "SelectToEnd", "Enter": "ExecuteCommand", "CtrlH": "Backspace", "Backspace": "Backspace", "OldBackspace": "Backspace", "Alt-CtrlH": "DeleteWordLeft", "Alt-Backspace": "DeleteWordLeft", "Tab": "CommandComplete", "Backtab": "CycleAutocompleteBack", "Ctrl-z": "Undo", "Ctrl-y": "Redo", "Ctrl-c": "Copy|CopyLine", "Ctrl-x": "Cut|CutLine", "Ctrl-k": "CutLine", "Ctrl-v": "Paste", "Home": "StartOfTextToggle", "End": "EndOfLine", "CtrlHome": "CursorStart", "CtrlEnd": "CursorEnd", "Delete": "Delete", "Ctrl-q": "AbortCommand", "Ctrl-e": "EndOfLine", "Ctrl-a": "StartOfLine", "Ctrl-w": "DeleteWordLeft", "Insert": "ToggleOverwriteMode", "Ctrl-b": "WordLeft", "Ctrl-f": "WordRight", "Ctrl-d": "DeleteWordLeft", "Ctrl-m": "ExecuteCommand", "Ctrl-n": "HistoryDown", "Ctrl-p": "HistoryUp", "Ctrl-u": "SelectToStart", // Emacs-style keybindings "Alt-f": "WordRight", "Alt-b": "WordLeft", "Alt-a": "StartOfText", "Alt-e": "EndOfLine", // Integration with file managers "F10": "AbortCommand", "Esc": "AbortCommand", // Mouse bindings "MouseWheelUp": "HistoryUp", "MouseWheelDown": "HistoryDown", "MouseLeft": "MousePress", "MouseLeftDrag": "MouseDrag", "MouseLeftRelease": "MouseRelease", "MouseMiddle": "PastePrimary" } } ``` ## Final notes Note: On some old terminal emulators and on Windows machines, `Ctrl-h` should be used for backspace. Additionally, alt keys can be bound by using `Alt-key`. For example `Alt-a` or `Alt-Up`. Micro supports an optional `-` between modifiers like `Alt` and `Ctrl` so `Alt-a` could be rewritten as `Alta` (case matters for alt bindings). This is why in the default keybindings you can see `AltShiftLeft` instead of `Alt-ShiftLeft` (they are equivalent). Please note that terminal emulators are strange applications and micro only receives key events that the terminal decides to send. Some terminal emulators may not send certain events even if this document says micro can receive the event. To see exactly what micro receives from the terminal when you press a key, run the `> raw` command. zyedidia-micro-6a62575/runtime/help/help.md0000664000175000017510000000506015125206537020131 0ustar nileshnilesh# Micro help text Micro is an easy to use, intuitive, text editor that takes advantage of the full capabilities of modern terminals. Micro can be controlled by commands entered on the command bar, or with keybindings. To open the command bar, press `Ctrl-e`: the `>` prompt will display. From now on, when the documentation shows a command to run (such as `> help`), press `Ctrl-e` and type the command followed by enter. For a list of the default keybindings, run `> help defaultkeys`. For more information on keybindings, see `> help keybindings`. To toggle a short list of important keybindings, press Alt-g. ## Quick-start To quit, press `Ctrl-q`. Save by pressing `Ctrl-s`. Press `Ctrl-e`, as previously mentioned, to start typing commands. To see which commands are available, at the prompt, press tab, or view the help topic with `> help commands`. Move the cursor around with the mouse or with the arrow keys. Enter text simply by pressing character keys. If the colorscheme doesn't look good, you can change it with `> set colorscheme ...`. You can press tab to see the available colorschemes, or see more information about colorschemes and syntax highlighting with `> help colors`. Press `Ctrl-w` to move between splits, and type `> vsplit filename` or `> hsplit filename` to open a new split. ## Accessing more help Micro has a built-in help system which can be accessed with the `> help` command. To view help for the various available topics, press `Ctrl-e` to access command mode and type in `> help` followed by a topic. Typing just `> help` will open this page. Here are the available help topics: * `tutorial`: A brief tutorial which gives an overview of all the other help topics * `keybindings`: Gives a full list of the default keybindings as well as how to rebind them * `defaultkeys`: Gives a more straight-forward list of the hotkey commands and what they do * `commands`: Gives a list of all the commands and what they do * `options`: Gives a list of all the options you can customize * `plugins`: Explains how micro's plugin system works and how to create your own plugins * `colors`: Explains micro's colorscheme and syntax highlighting engine and how to create your own colorschemes or add new languages to the engine For example, to open the help page on plugins you would run `> help plugins`. I recommend looking at the `tutorial` help file because it is short for each section and gives concrete examples of how to use the various configuration options in micro. However, it does not give the in-depth documentation that the other topics provide. zyedidia-micro-6a62575/runtime/help/defaultkeys.md0000664000175000017510000002153115125206537021522 0ustar nileshnilesh# Default Keys Below are simple charts of the default hotkeys and their functions. For more information about binding custom hotkeys or changing default bindings, please run `> help keybindings` Please remember that *all* keys here are rebindable! If you don't like it, you can change it! ### Power user | Key | Description of function | |---------- |-------------------------------------------------------------------------------------------------- | | Ctrl-e | Open a command prompt for running commands (see `> help commands` for a list of valid commands). | | Tab | In command prompt, it will autocomplete if possible. | | Ctrl-b | Run a shell command (this will close micro while your command executes). | ### Navigation | Key | Description of function | |---------------------------- |------------------------------------------------------------------------------------------ | | Arrows | Move the cursor around | | Shift-arrows | Move and select text | | Alt(Ctrl on Mac)-LeftArrow | Move to the beginning of the current line | | Alt(Ctrl on Mac)-RightArrow | Move to the end of the current line | | Home | Move to the beginning of text on the current line | | End | Move to the end of the current line | | Ctrl(Alt on Mac)-LeftArrow | Move cursor one word left | | Ctrl(Alt on Mac)-RightArrow | Move cursor one word right | | Alt-{ | Move cursor to previous empty line, or beginning of document | | Alt-} | Move cursor to next empty line, or end of document | | PageUp | Move cursor up one page | | PageDown | Move cursor down one page | | Ctrl-Home or Ctrl-UpArrow | Move cursor to start of document | | Ctrl-End or Ctrl-DownArrow | Move cursor to end of document | | Ctrl-l | Jump to a line in the file (prompts with #) | | Ctrl-w | Cycle between splits in the current tab (use `> vsplit` or `> hsplit` to create a split) | ### Tabs | Key | Description of function | |-------- |-------------------------- | | Ctrl-t | Open a new tab | | Alt-, | Previous tab | | Alt-. | Next tab | ### Find Operations | Key | Description of function | |---------- |------------------------------------------ | | Ctrl-f | Find (opens prompt) | | Ctrl-n | Find next instance of current search | | Ctrl-p | Find previous instance of current search | Note: `Ctrl-n` and `Ctrl-p` should be used from the main buffer, not from inside the search prompt. After `Ctrl-f`, press enter to complete the search and then you can use `Ctrl-n` and `Ctrl-p` to cycle through matches. ### File Operations | Key | Description of function | |---------- |------------------------------------------------------------------ | | Ctrl-q | Close current file (quits micro if this is the last file open) | | Ctrl-o | Open a file (prompts for filename) | | Ctrl-s | Save current file | ### Text operations | Key | Description of function | |------------------------------------ |------------------------------------------ | | Ctrl(Alt on Mac)-Shift-RightArrow | Select word right | | Ctrl(Alt on Mac)-Shift-LeftArrow | Select word left | | Alt(Ctrl on Mac)-Shift-LeftArrow | Select to start of current line | | Alt(Ctrl on Mac)-Shift-RightArrow | Select to end of current line | | Shift-Home | Select to start of current line | | Shift-End | Select to end of current line | | Ctrl-Shift-UpArrow | Select to start of file | | Ctrl-Shift-DownArrow | Select to end of file | | Ctrl-x | Cut selected text | | Ctrl-c | Copy selected text | | Ctrl-v | Paste | | Ctrl-k | Cut current line | | Ctrl-d | Duplicate current line | | Ctrl-z | Undo | | Ctrl-y | Redo | | Alt-UpArrow | Move current line or selected lines up | | Alt-DownArrow | Move current line or selected lines down | | Alt-Backspace or Alt-Ctrl-h | Delete word left | | Ctrl-a | Select all | | Tab | Indent selected text | | Shift-Tab | Unindent selected text | ### Macros | Key | Description of function | |---------- |---------------------------------------------------------------------------------- | | Ctrl-u | Toggle macro recording (press Ctrl-u to start recording and press again to stop) | | Ctrl-j | Run latest recorded macro | ### Multiple cursors | Key | Description of function | |------------------ |---------------------------------------------------------------------------------------------- | | Alt-n | Create new multiple cursor from selection (will select current word if no current selection) | | Alt-Shift-Up | Spawn a new cursor on the line above the current one | | Alt-Shift-Down | Spawn a new cursor on the line below the current one | | Alt-p | Remove latest multiple cursor | | Alt-c | Remove all multiple cursors (cancel) | | Alt-x | Skip multiple cursor selection | | Alt-m | Spawn a new cursor at the beginning of every line in the current selection | | Ctrl-MouseLeft | Place a multiple cursor at any location | ### Other | Key | Description of function | |---------- |-------------------------------------------------------------------------------------- | | Ctrl-g | Open help file | | Ctrl-h | Backspace (old terminals do not support the backspace key and use Ctrl+H instead) | | Ctrl-r | Toggle the line number ruler | ### Emacs style actions | Key | Description of function | |---------- |-------------------------- | | Alt-f | Next word | | Alt-b | Previous word | | Alt-a | Move to start of line | | Alt-e | Move to end of line | ### Function keys. Warning! The function keys may not work in all terminals! | Key | Description of function | |------ |-------------------------- | | F1 | Open help | | F2 | Save | | F3 | Find | | F4 | Quit | | F7 | Find | | F10 | Quit | zyedidia-micro-6a62575/runtime/help/copypaste.md0000664000175000017510000001523615125206537021216 0ustar nileshnileshCopy and paste are essential features in micro but can be confusing to get right especially when running micro over SSH because there are multiple methods. This help document will explain the various methods for copying and pasting, how they work, and the best methods for doing so over SSH. # OSC 52 (terminal clipboard) If possible, setting the `clipboard` option to `terminal` will give best results because it will work over SSH and locally. However, there is limited support among terminal emulators for the terminal clipboard (which uses the OSC 52 protocol to communicate clipboard contents). Here is a list of terminal emulators and their status: * `Kitty`: supported, but only writing is enabled by default. To enable reading, add `read-primary` and `read-clipboard` to the `clipboard_control` option. * `iTerm2`: only copying (writing to clipboard) is supported. Must be enabled in `Preferences->General-> Selection->Applications in terminal may access clipboard`. You can use `Command-v` to paste. * `st`: supported. * `rxvt-unicode`: not natively supported, but there is a Perl extension [here](https://anti.teamidiot.de/static/nei/*/Code/urxvt/). * `xterm`: supported, but disabled by default. It can be enabled by putting the following in `.Xresources` or `.Xdefaults`: `XTerm*disallowedWindowOps: 20,21,SetXprop`. * `gnome-terminal`: does not support OSC 52. * `alacritty`: supported. Since 0.13.0, reading has been disabled by default. To reenable it, set the `terminal.osc52` option to `CopyPaste`. * `foot`: supported. * `wezterm`: only copying (writing to clipboard) is supported. **Summary:** If you want copy and paste to work over SSH, then you should set `clipboard` to `terminal`, and make sure your terminal supports OSC 52. # Pasting ## Recommendations (TL;DR) The recommended method of pasting is the following: * If you are not working over SSH, use the micro keybinding (`Ctrl-v` by default) to perform pastes. If on Linux, install `xclip` or `xsel` beforehand. * If you are working over SSH, use the terminal keybinding (`Ctrl-Shift-v` or `Command-v`) to perform pastes. If your terminal does not support bracketed paste, when performing a paste first enable the `paste` option, and when finished disable the option. ## Micro paste events Micro is an application that runs within the terminal. This means that the terminal sends micro events, such as key events, mouse events, resize events, and paste events. Micro's default keybinding for paste is `Ctrl-v`. This means that when micro receives the key event saying `Ctrl-v` has been pressed from the terminal, it will attempt to access the system clipboard and effect a paste. The system clipboard will be accessed through `pbpaste` on MacOS (installed by default), `xclip` or `xsel` on Linux (these applications must be installed by the user) or a system call on Windows. ## Terminal paste events For certain keypresses, the terminal will not send an event to micro and will instead do something itself. In this document, such keypresses will be called "terminal keybindings." Often there will be a terminal keybinding for pasting and copying. On MacOS these are Command-v and Command-c and on Linux `Ctrl-Shift-v` and `Ctrl-Shift-c`. When the terminal keybinding for paste is executed, your terminal will access the system clipboard, and send micro either a paste event or a list of key events (one key for each character in the paste), depending on whether or not your terminal supports sending paste events (called bracketed paste). If your terminal supports bracketed paste, then it will send a paste event and everything will work well. However, if your terminal sends a list of key events, this can cause issues because micro will think you manually entered each character and may add closing brackets or automatic indentation, which will mess up the pasted text. To avoid this, you can temporarily enable the `paste` option while you perform the paste. When paste option is on, micro will aggregate lists of multiple key events into larger paste events. It is a good idea to disable the `paste` option during normal use as occasionally if you are typing quickly, the terminal will send the key events as lists of characters that were in fact manually entered. ## Pasting over SSH When working over SSH, micro is running on the remote machine and your terminal is running on your local machine. Therefore if you would like to paste, using `Ctrl-v` (micro's keybinding) will not work because when micro attempts to access the system clipboard, it will access the remote machine's clipboard rather than the local machine's clipboard. On the other hand, the terminal keybinding for paste will access your local clipboard and send the text over the network as a paste event, which is what you want. # Copying # Recommendations (TL;DR) The recommended method of copying is the following: * If you are not working over SSH, use the micro keybinding (`Ctrl-c` by default) to perform copies. If on Linux, install `xclip` or `xsel` beforehand. * If you are working over SSH, use the terminal keybinding (`Ctrl-Shift-c` or `Command-c`) to perform copies. You must first disable the `mouse` option to perform a terminal selection, and you may wish to disable line numbers and diff indicators (`ruler` and `diffgutter` options) and close other splits. This method will only be able to copy characters that are displayed on the screen (you will not be able to copy more than one page's worth of characters). Copying follows a similar discussion to the one above about pasting. The primary difference is before performing a copy, the application doing the copy must be told what text needs to be copied. Micro has a keybinding (`Ctrl-c`) for copying and will access the system clipboard to perform the copy. The text that micro will copy into is the text that is currently selected in micro (usually such text is displayed with a white background). When the `mouse` option is enabled, the mouse can be used to select text, as well as other keybindings, such as ShiftLeft, etc... The terminal also has a keybinding (`Ctrl-Shift-c` or `Command-c`) to perform a copy, and the text that it copies is the text selected by the terminal's selection (*not* micro's selection). To select text with the terminal selection, micro's mouse support must first be disabled by turning the `mouse` option off. The terminal, unlike micro, has no sense of different buffers/splits and what the different characters being displayed are. This means that for copying multiple lines using the terminal selection, you should first disable line numbers and diff indicators (turn off the `ruler` and `diffgutter` options), otherwise they might be part of your selection and copied. zyedidia-micro-6a62575/runtime/help/commands.md0000664000175000017510000001562015125206537021005 0ustar nileshnilesh# Command bar The command bar is opened by pressing `Ctrl-e`. It is a single-line buffer, meaning that all keybindings from a normal buffer are supported (as well as mouse and selection). When running a command, you can use extra syntax that micro will expand before running the command. To use an argument with a space in it, put it in quotes. The command bar parser uses the same rules for parsing arguments that `/bin/sh` would use (single quotes, double quotes, escaping). The command bar does not look up environment variables. # Commands Micro provides the following commands that can be executed at the command-bar by pressing `Ctrl-e` and entering the command. Arguments are placed in single quotes here but these are not necessary when entering the command in micro. * `bind 'key' 'action'`: creates a keybinding from key to action. See the `keybindings` documentation for more information about binding keys. This command will modify `bindings.json` and overwrite any bindings to `key` that already exist. * `help ['topic'] ['flags']`: opens the corresponding help topics. If no topic is provided opens the default help screen. If multiple topics are provided (separated via ` `) they are opened all as splits. Help topics are stored as `.md` files in the `runtime/help` directory of the source tree, which is embedded in the final binary. The `flags` are optional. * `-hsplit`: Opens the help topic in a horizontal split * `-vsplit`: Opens the help topic in a vertical split The default split type is defined by the global `helpsplit` option. * `save ['filename']`: saves the current buffer. If the file is provided it will 'save as' the filename. * `quit`: quits micro. * `goto 'line[:col]'`: goes to the given absolute line (and optional column) number. A negative number can be passed to go inward from the end of the file. Example: -5 goes to the 5th-last line in the file. * `jump 'line[:col]'`: goes to the given relative number from the current line (and optional absolute column) number. Example: -5 jumps 5 lines up in the file, while (+)3 jumps 3 lines down. * `replace 'search' 'value' ['flags']`: This will replace `search` with `value`. The `flags` are optional. Possible flags are: * `-a`: Replace all occurrences at once * `-l`: Do a literal search instead of a regex search Note that `search` must be a valid regex (unless `-l` is passed). If one of the arguments does not have any spaces in it, you may omit the quotes. In case the search is done non-literal (without `-l`), the 'value' is interpreted as a template: * `$3` or `${3}` substitutes the submatch of the 3rd (capturing group) * `$foo` or `${foo}` substitutes the submatch of the (?Pnamed group) * You have to write `$$` to substitute a literal dollar. * `replaceall 'search' 'value'`: this will replace all occurrences of `search` with `value` without user confirmation. See `replace` command for more information. * `set 'option' 'value'`: sets the option to value. See the `options` help topic for a list of options you can set. This will modify your `settings.json` with the new value. * `setlocal 'option' 'value'`: sets the option to value locally (only in the current buffer). This will *not* modify `settings.json`. * `toggle 'option'`: toggles the option. Only works with options that accept exactly two values. This will modify your `settings.json` with the new value. * `togglelocal 'option'`: toggles the option locally (only in the current buffer). Only works with options that accept exactly two values. This will *not* modify `settings.json`. * `reset 'option'`: resets the given option to its default value. * `show 'option'`: shows the current value of the given option. * `showkey 'key'`: Show the action(s) bound to a given key. For example running `> showkey Ctrl-c` will display `Copy`. * `run 'sh-command'`: runs the given shell command in the background. The command's output will be displayed in one line when it finishes running. * `vsplit ['filename']`: opens a vertical split with `filename`. If no filename is provided, a vertical split is opened with an empty buffer. If multiple files are provided (separated via ` `) they are opened all as splits. * `hsplit ['filename']`: same as `vsplit` but opens a horizontal split instead of a vertical split. * `tab ['filename']`: opens the given file in a new tab. If no filename is provided, a tab is opened with an empty buffer. If multiple files are provided (separated via ` `) they are opened all as tabs. * `tabmove '[-+]n'`: Moves the active tab to another slot. `n` is an integer. If `n` is prefixed with `-` or `+`, then it represents a relative position (e.g. `tabmove +2` moves the tab to the right by `2`). If `n` has no prefix, it represents an absolute position (e.g. `tabmove 2` moves the tab to slot `2`). * `tabswitch 'tab'`: This command will switch to the specified tab. The `tab` can either be a tab number, or a name of a tab. * `textfilter 'sh-command'`: filters the current selection through a shell command as standard input and replaces the selection with the stdout of the shell command. For example, to sort a list of numbers, first select them, and then execute `> textfilter sort -n`. * `log`: opens a log of all messages and debug statements. * `plugin list`: lists all installed plugins. * `plugin install 'pl'`: install a plugin. * `plugin remove 'pl'`: remove a plugin. * `plugin update ['pl']`: update a plugin (if no arguments are provided updates all plugins). * `plugin search 'pl'`: search available plugins for a keyword. * `plugin available`: show available plugins that can be installed. * `reload`: reloads all runtime files (settings, keybindings, syntax files, colorschemes, plugins). All plugins will be unloaded by running their `deinit()` function (if it exists), and then loaded again by calling the `preinit()`, `init()` and `postinit()` functions (if they exist). * `cd 'path'`: Change the working directory to the given `path`. * `pwd`: Print the current working directory. * `open 'filename'`: Open a file in the current buffer. * `reopen`: Reopens the current file from disk. * `retab`: Replaces all leading tabs with spaces or leading spaces with tabs depending on the value of `tabstospaces`. * `raw`: micro will open a new tab and show the escape sequence for every event it receives from the terminal. This shows you what micro actually sees from the terminal and helps you see which bindings aren't possible and why. This is most useful for debugging keybindings. * `term ['exec']`: Open a terminal emulator running the given executable. If no executable is given, this will open the default shell in the terminal emulator. --- The following commands are provided by the default plugins: * `lint`: Lint the current file for errors. * `comment`: automatically comment or uncomment current selection or line. zyedidia-micro-6a62575/runtime/help/colors.md0000664000175000017510000003405015125206537020503 0ustar nileshnilesh# Colors This help page aims to cover two aspects of micro's syntax highlighting engine: * How to create colorschemes and use them. * How to create syntax files to add to the list of languages micro can highlight. ## Colorschemes To change your colorscheme, press `Ctrl-e` in micro to bring up the command prompt, and type: ``` set colorscheme twilight ``` (or whichever colorscheme you choose). Micro comes with a number of colorschemes by default. The colorschemes that you can display will depend on what kind of color support your terminal has. Omit color-link default "[fg color],[bg color]" will make the background color match the terminal's, and transparency if set. Modern terminals tend to have a palette of 16 user-configurable colors (these colors can often be configured in the terminal preferences), and additional color support comes in three flavors. * 16-color: A colorscheme that uses the 16 default colors will always work but will only look good if the 16 default colors have been configured to the user's liking. Using a colorscheme that only uses the 16 colors from the terminal palette will also preserve the terminal's theme from other applications since the terminal will often use those same colors for other applications. Default colorschemes of this type include `simple` and `solarized`. * 256-color: Almost all terminals support displaying an additional 240 colors on top of the 16 user-configurable colors (creating 256 colors total). Colorschemes which use 256-color are portable because they will look the same regardless of the configured 16-color palette. However, the color range is fairly limited due to the small number of colors available. Default 256-color colorschemes include `monokai`, `twilight`, `zenburn`, `darcula` and more. * true-color: Some terminals support displaying "true color" with 16 million colors using standard RGB values. This mode will be able to support displaying any colorscheme, but it should be noted that the user-configured 16-color palette is ignored when using true-color mode (this means the colors while using the terminal emulator will be slightly off). Not all terminals support true color but at this point most do (see below). True-color colorschemes in micro typically end with `-tc`, such as `solarized-tc`, `atom-dark`, `material-tc`, etc... If true color is not enabled but a true color colorscheme is used, micro will do its best to approximate the colors to the available 256 colors. Here is the list of colorschemes: ### 256 color These should work and look nice in most terminals. I recommend these themes the most. * `monokai` (also the `default` colorscheme) * `zenburn` * `gruvbox` * `darcula` * `twilight` * `railscast` * `bubblegum` (light theme) ### 16 color These may vary widely based on the 16 colors selected for your terminal. * `simple` * `solarized` (must have the solarized color palette in your terminal to use this colorscheme properly) * `cmc-16` * `cmc-paper` * `geany` ### True color Micro enables true color support by default as long as it detects that the terminal supports it (which is usually indicated by the environment variable `COLORTERM` being set to `truecolor`, `24bit` or `24-bit`). You can also force enabling it unconditionally by setting the option `truecolor` to `on` (or alternatively by setting the environment variable `MICRO_TRUECOLOR` to 1, which is supported for backward compatibility). * `solarized-tc`: this is the solarized colorscheme for true color. * `atom-dark`: this colorscheme is based off of Atom's "dark" colorscheme. * `cmc-tc`: A true colour variant of the cmc theme. It requires true color to look its best. Use cmc-16 if your terminal doesn't support true color. * `gruvbox-tc`: The true color version of the gruvbox colorscheme * `material-tc`: Colorscheme based off of Google's Material Design palette ## Creating a Colorscheme Micro's colorschemes are also extremely simple to create. The default ones can be found [here](https://github.com/zyedidia/micro/tree/master/runtime/colorschemes). Custom colorschemes should be placed in the `~/.config/micro/colorschemes` directory. A number of custom directives are placed in a `.micro` file. Colorschemes are typically only 18-30 lines in total. To create the colorscheme you need to link highlight groups with actual colors. This is done using the `color-link` command. For example, to highlight all comments in green, you would use the command: ``` color-link comment "green" ``` Background colors can also be specified with a comma: ``` color-link comment "green,blue" ``` This will give the comments a blue background. If you would like no foreground you can just use a comma with nothing in front: ``` color-link comment ",blue" ``` You can also put bold, italic, or underline in front of the color: ``` color-link comment "bold red" ``` --- There are three different ways to specify the color. Color terminals usually have 16 colors that are preset by the user. This means that you cannot depend on those colors always being the same. You can use those colors with the names `black, red, green, yellow, blue, magenta, cyan, white` and the bright variants of each one (brightblack, brightred...). Then you can use the terminals 256 colors by using their numbers 1-256 (numbers 1-16 will refer to the named colors). If the user's terminal supports true color, then you can also specify colors exactly using their hex codes. If the terminal is not true color but micro is told to use a true color colorscheme it will attempt to map the colors to the available 256 colors. Generally colorschemes which require true color terminals to look good are marked with a `-tc` suffix and colorschemes which supply a white background are marked with a `-paper` suffix. --- Here is a list of the colorscheme groups that you can use: * default (color of the background and foreground for unhighlighted text) * comment * identifier * constant * statement * symbol * preproc * type * special * underlined * error * todo * selection (Color of the text selection) * statusline (Color of the statusline) * statusline.inactive (Color of the statusline of inactive split panes) * statusline.suggestions (Color of the autocomplete suggestions menu) * tabbar (Color of the tabbar that lists open files) * tabbar.active (Color of the active tab in the tabbar) * indent-char (Color of the character which indicates tabs if the option is enabled) * line-number * gutter-info * gutter-error * gutter-warning * diff-added * diff-modified * diff-deleted * cursor-line * current-line-number * color-column * ignore * scrollbar * divider (Color of the divider between vertical splits) * message (Color of messages in the bottom line of the screen) * error-message (Color of error messages in the bottom line of the screen) * match-brace (Color of matching brackets when `matchbracestyle` is set to `highlight`) * hlsearch (Color of highlighted search results when `hlsearch` is enabled) * tab-error (Color of tab vs space errors when `hltaberrors` is enabled) * trailingws (Color of trailing whitespaces when `hltrailingws` is enabled) Colorschemes must be placed in the `~/.config/micro/colorschemes` directory to be used. --- In addition to the main colorscheme groups, there are subgroups that you can specify by adding `.subgroup` to the group. If you're creating your own custom syntax files, you can make use of your own subgroups. If micro can't match the subgroup, it'll default to the root group, so it's safe and recommended to use subgroups in your custom syntax files. For example if `constant.string` is found in your colorscheme, micro will us that for highlighting strings. If it's not found, it will use constant instead. Micro tries to match the largest set of groups it can find in the colorscheme definitions, so if, for example `constant.bool.true` is found then micro will use that. If `constant.bool.true` is not found but `constant.bool` is found micro will use `constant.bool`. If not, it uses `constant`. Here's a list of subgroups used in micro's built-in syntax files. * comment.bright (Some filetypes have distinctions between types of comments) * constant.bool * constant.bool.true * constant.bool.false * constant.number * constant.specialChar * constant.string * constant.string.url * identifier.class (Also used for functions) * identifier.macro * identifier.var * preproc.shebang (The #! at the beginning of a file that tells the os what script interpreter to use) * symbol.brackets (`{}()[]` and sometimes `<>`) * symbol.operator (Color operator symbols differently) * symbol.tag (For html tags, among other things) * type.keyword (If you want a special highlight for keywords like `private`) In the future, plugins may also be able to use color groups for styling. --- Last but not least it's even possible to use `include` followed by the colorscheme name as string to include a different colorscheme within a new one. Additionally the groups can then be extended or overwritten. The `default.micro` theme can be seen as an example, which links to the chosen default colorscheme. ## Syntax files The syntax files are written in yaml-format and specify how to highlight languages. Micro's builtin syntax highlighting tries very hard to be sane, sensible and provide ample coverage of the meaningful elements of a language. Micro has syntax files built in for over 100 languages now! However, there may be situations where you find Micro's highlighting to be insufficient or not to your liking. The good news is that you can create your own syntax files, and place them in `~/.config/micro/syntax` and Micro will use those instead. ### Filetype definition You must start the syntax file by declaring the filetype: ``` filetype: go ``` ### Detect definition Then you must provide information about how to detect the filetype: ``` detect: filename: "\\.go$" ``` Micro will match this regex against a given filename to detect the filetype. In addition to the `filename` regex (or even instead of it) you can provide a `header` regex that will check the first line of the file. For example: ``` detect: filename: "\\.ya?ml$" header: "%YAML" ``` This is useful in cases when the given file name is not sufficient to determine the filetype, e.g. with the above example, if a YAML file has no `.yaml` extension but may contain a `%YAML` directive in its first line. `filename` takes precedence over `header`, i.e. if there is a syntax file that matches the file with a filetype by the `filename` and another syntax file that matches the same file with another filetype by the `header`, the first filetype will be used. Finally, in addition to `filename` and/or `header` (but not instead of them) you may also provide an optional `signature` regex which is useful for resolving ambiguities when there are multiple syntax files matching the same file with different filetypes. If a `signature` regex is given, micro will match a certain amount of first lines in the file (this amount is determined by the `detectlimit` option) against this regex, and if any of the lines match, this syntax file's filetype will be preferred over other matching filetypes. For example, to distinguish C++ header files from C and Objective-C header files that have the same `.h` extension: ``` detect: filename: "\\.c(c|pp|xx)$|\\.h(h|pp|xx)?$" signature: "namespace|template|public|protected|private" ``` ### Syntax rules Next you must provide the syntax highlighting rules. There are two types of rules: patterns and regions. A pattern is matched on a single line and usually a single word as well. A region highlights between two patterns over multiple lines and may have rules of its own inside the region. Here are some example patterns in Go: ``` rules: - special: "\\b(break|case|continue|default|go|goto|range|return)\\b" - statement: "\\b(else|for|if|switch)\\b" - preproc: "\\b(package|import|const|var|type|struct|func|go|defer|iota)\\b" ``` The order of patterns does matter as patterns lower in the file will overwrite the ones defined above them. And here are some example regions for Go: ``` - constant.string: start: "\"" end: "\"" rules: - constant.specialChar: "%." - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]" - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})" - comment: start: "//" end: "$" rules: - todo: "(TODO|XXX|FIXME):?" - comment: start: "/\\*" end: "\\*/" rules: - todo: "(TODO|XXX|FIXME):?" ``` Notice how the regions may contain rules inside of them. Any inner rules that are matched are then skipped when searching for the end of the region. For example, when highlighting `"foo \" bar"`, since `\"` is matched by an inner rule in the region, it is skipped. Likewise for `"foo \\" bar`, since `\\` is matched by an inner rule, it is skipped, and then the `"` is found and the string ends at the correct place. You may also explicitly mark skip regexes if you don't want them to be highlighted. For example: ``` - constant.string: start: "\"" end: "\"" skip: "\\." ``` #### Includes You may also include rules from other syntax files as embedded languages. For example, the following is possible for html: ``` - default: start: "" end: "" rules: - include: "javascript" - default: start: "" end: "" rules: - include: "css" ``` Note that nested include (i.e. including syntax files that include other syntax files) is not supported yet. ### Default syntax highlighting If micro cannot detect the filetype of the file, it falls back to using the default syntax highlighting for it, which highlights just the bare minimum: email addresses, URLs etc. Just like in other cases, you can override the default highlighting by adding your own custom `default.yaml` file to `~/.config/micro/syntax`. For example, if you work with various config files that use the `#` sign to mark the beginning of a comment, you can use the following custom `default.yaml` to highlight those comments by default: ``` filetype: unknown detect: filename: "" rules: - comment: "(^|\\s)#.*$" ``` zyedidia-micro-6a62575/runtime/colorschemes/0000775000175000017510000000000015125206537020414 5ustar nileshnileshzyedidia-micro-6a62575/runtime/colorschemes/zenburn.micro0000664000175000017510000000164015125206537023133 0ustar nileshnileshcolor-link default "188,237" color-link comment "108,237" color-link constant.string "174,237" color-link constant.number "116,237" color-link constant "181,237" color-link identifier "223,237" color-link statement "223,237" color-link symbol "223,237" color-link preproc "223,237" color-link type "187,237" color-link special "181,237" color-link underlined "188,237" color-link error "115,236" color-link todo "bold 254,237" color-link hlsearch "230,22" color-link statusline "186,236" color-link tabbar "186,236" color-link indent-char "238,237" color-link line-number "248,238" color-link diff-added "34" color-link diff-modified "214" color-link diff-deleted "160" color-link gutter-error "237,174" color-link gutter-warning "174,237" color-link cursor-line "238" color-link color-column "238" color-link current-line-number "188,237" color-link match-brace "237,223" color-link tab-error "167" color-link trailingws "167" zyedidia-micro-6a62575/runtime/colorschemes/twilight.micro0000664000175000017510000000253015125206537023302 0ustar nileshnilesh# Twilight color scheme color-link default "#F8F8F8,#141414" color-link color-column "#1B1B1B" color-link comment "#5F5A60" color-link constant "#CF6A4C" #color-link constant.number "#CF6A4C" color-link constant.specialChar "#DDF2A4" color-link constant.string "#8F9D6A" color-link current-line-number "#868686,#1B1B1B" color-link cursor-line "#1B1B1B" color-link divider "#1E1E1E" color-link error "#D2A8A1" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error "#9B859D" color-link gutter-warning "#9B859D" color-link hlsearch "#141414,#C0C000" color-link identifier "#9B703F" color-link identifier.class "#DAD085" color-link identifier.var "#7587A6" color-link indent-char "#515151" color-link line-number "#868686,#1B1B1B" color-link current-line-number "#868686,#141414" color-link preproc "#E0C589" color-link special "#E0C589" color-link statement "#CDA869" color-link statusline "#515151,#1E1E1E" color-link symbol "#AC885B" color-link symbol.brackets "#F8F8F8" color-link symbol.operator "#CDA869" color-link symbol.tag "#AC885B" color-link tabbar "#F2F0EC,#2D2D2D" color-link todo "#8B98AB" color-link type "#F9EE98" color-link type.keyword "#CDA869" color-link underlined "#8996A8" color-link match-brace "#141414,#E0C589" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/colorschemes/sunny-day.micro0000664000175000017510000000145215125206537023400 0ustar nileshnileshcolor-link default "0,230" color-link comment "244" color-link constant.string "17" color-link constant "88" color-link identifier "22" color-link statement "0,230" color-link symbol "89" color-link preproc "22" color-link type "88" color-link special "22" color-link underlined "61,230" color-link error "88" color-link todo "210" color-link hlsearch "0,253" color-link statusline "233,229" color-link tabbar "233,229" color-link indent-char "229" color-link line-number "244" color-link diff-added "34" color-link diff-modified "214" color-link diff-deleted "160" color-link gutter-error "88" color-link gutter-warning "88" color-link cursor-line "229" #color-link color-column "196" color-link current-line-number "246" color-link match-brace "230,22" color-link tab-error "210" color-link trailingws "210" zyedidia-micro-6a62575/runtime/colorschemes/solarized.micro0000664000175000017510000000200715125206537023442 0ustar nileshnileshcolor-link comment "bold brightgreen" color-link constant "cyan" color-link constant.specialChar "red" color-link identifier "blue" color-link statement "green" color-link symbol "green" color-link preproc "brightred" color-link type "yellow" color-link special "blue" color-link underlined "magenta" color-link error "bold brightred" color-link todo "bold magenta" color-link hlsearch "black,yellow" color-link statusline "black,brightblue" color-link tabbar "black,brightblue" color-link indent-char "black" color-link line-number "bold brightgreen,black" color-link current-line-number "bold brightgreen,default" color-link diff-added "green" color-link diff-modified "yellow" color-link diff-deleted "red" color-link gutter-error "black,brightred" color-link gutter-warning "brightred,default" color-link cursor-line "black" color-link color-column "black" color-link type.extended "default" color-link symbol.brackets "default" color-link match-brace ",blue" color-link tab-error "brightred" color-link trailingws "brightred" zyedidia-micro-6a62575/runtime/colorschemes/solarized-tc.micro0000664000175000017510000000225315125206537024051 0ustar nileshnileshcolor-link default "#839496,#002833" color-link comment "#586E75,#002833" color-link identifier "#268BD2,#002833" color-link constant "#2AA198,#002833" color-link constant.specialChar "#DC322F,#002833" color-link statement "#859900,#002833" color-link symbol "#859900,#002833" color-link preproc "#CB4B16,#002833" color-link type "#B58900,#002833" color-link special "#268BD2,#002833" color-link underlined "#D33682,#002833" color-link error "bold #CB4B16,#002833" color-link todo "bold #D33682,#002833" color-link hlsearch "#002833,#B58900" color-link statusline "#003541,#839496" color-link tabbar "#003541,#839496" color-link indent-char "#003541,#002833" color-link line-number "#586E75,#003541" color-link current-line-number "#586E75,#002833" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error "#003541,#CB4B16" color-link gutter-warning "#CB4B16,#002833" color-link cursor-line "#003541" color-link color-column "#003541" color-link type.extended "#839496,#002833" color-link symbol.brackets "#839496,#002833" color-link match-brace "#002833,#268BD2" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/colorschemes/simple.micro0000664000175000017510000000205415125206537022741 0ustar nileshnileshcolor-link comment "blue" color-link constant "red" color-link identifier "cyan" color-link statement "yellow" color-link symbol "yellow" color-link preproc "magenta" color-link type "green" color-link special "magenta" color-link ignore "default" color-link error ",brightred" color-link todo ",brightyellow" color-link hlsearch "black,yellow" color-link statusline "black,white" color-link indent-char "black" color-link line-number "yellow" color-link current-line-number "red" color-link diff-added "green" color-link diff-modified "yellow" color-link diff-deleted "red" color-link gutter-error ",red" color-link gutter-warning "red" #Cursor line causes readability issues. Disabled for now. #color-link cursor-line "white,black" color-link color-column "white" #No extended types. (bool in C) color-link type.extended "default" #No bracket highlighting. color-link symbol.brackets "default" #Color shebangs the comment color color-link preproc.shebang "comment" color-link match-brace ",magenta" color-link tab-error "brightred" color-link trailingws "brightred" zyedidia-micro-6a62575/runtime/colorschemes/railscast.micro0000664000175000017510000000261015125206537023433 0ustar nileshnileshcolor-link default "#e6e1dc,#2b2b2b" color-link comment "#bc9458,#2b2b2b" color-link statement "#cc7833,#2b2b2b" color-link constant "#a5c261,#2b2b2b" color-link constant.bool "#6d9cbe,#2b2b2b" color-link constant.specialChar "#459231,#2b2b2b" color-link type "#6d9cbe,#2b2b2b" color-link preproc "#cc7833,#2b2b2b" color-link special "#cc7833,#2b2b2b" color-link underlined "#cc7833,#2b2b2b" color-link todo "bold #cc7833,#2b2b2b" color-link error "bold #cc7833,#2b2b2b" color-link gutter-error "#cc7833,#11151C" color-link hlsearch "#e6e1dc,#474d5c" color-link indent-char "#414141,#2b2b2b" color-link line-number "#a1a1a1,#232323" color-link current-line-number "#e6e1dc,#2b2b2b" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-warning "#a5c261,#11151C" color-link symbol "#edb753,#2b2b2b" color-link symbol.operator "#cc7833,#2b2b2b" color-link symbol.brackets "#cc7833,#2b2b2b" color-link identifier "#edb753,#2b2b2b" color-link statusline "#b1b1b1,#232323" color-link tabbar "bold #b1b1b1,#232323" color-link cursor-line "#353535" color-link color-column "#353535" color-link space "underline #e6e1dc,#2b2b2b" color-link tab-error "#d75f5f" color-link trailingws "#d75f5f" #the Python syntax definition are wrong. This is not how you should do decorators! color-link brightgreen "#edb753,#2b2b2b" color-link match-brace "#2b2b2b,#a5c261" zyedidia-micro-6a62575/runtime/colorschemes/one-dark.micro0000664000175000017510000000247015125206537023152 0ustar nileshnileshcolor-link default "#ABB2BF,#21252C" color-link color-column "#282C34" color-link comment "#5C6370" color-link constant "#C678DD" color-link constant.number "#E5C07B" color-link constant.string "#98C379" color-link constant.string.char "#BDE6AD" color-link constant.specialChar "#DDF2A4" color-link current-line-number "#C6C6C6,#21252C" color-link cursor-line "#282C34" color-link divider "#ABB2BF" color-link error "#D2A8A1" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error "#9B859D" color-link gutter-warning "#9B859D" color-link hlsearch "#21252C,#E5C07B" color-link identifier "#61AFEF" color-link identifier.class "#C678DD" color-link identifier.var "#C678DD" color-link indent-char "#515151" color-link line-number "#636D83,#282C34" color-link preproc "#E0C589" color-link special "#E0C589" color-link statement "#C678DD" color-link statusline "#282828,#ABB2BF" color-link symbol "#AC885B" color-link symbol.brackets "#ABB2BF" color-link symbol.operator "#C678DD" color-link symbol.tag "#AC885B" color-link tabbar "#F2F0EC,#2D2D2D" color-link todo "#8B98AB" color-link type "#66D9EF" color-link type.keyword "#C678DD" color-link underlined "#8996A8" color-link match-brace "#21252C,#C678DD" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/colorschemes/monokai.micro0000664000175000017510000000243615125206537023111 0ustar nileshnileshcolor-link default "#F8F8F2,#282828" color-link comment "#75715E,#282828" color-link identifier "#66D9EF,#282828" color-link constant "#AE81FF,#282828" color-link constant.string "#E6DB74,#282828" color-link constant.string.char "#BDE6AD,#282828" color-link statement "#F92672,#282828" color-link symbol.operator "#F92672,#282828" color-link preproc "#CB4B16,#282828" color-link type "#66D9EF,#282828" color-link special "#A6E22E,#282828" color-link underlined "#D33682,#282828" color-link error "bold #CB4B16,#282828" color-link todo "bold #D33682,#282828" color-link hlsearch "#282828,#E6DB74" color-link statusline "#282828,#F8F8F2" color-link tabbar "#282828,#F8F8F2" color-link indent-char "#505050,#282828" color-link line-number "#AAAAAA,#323232" color-link current-line-number "#AAAAAA,#282828" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error "#CB4B16,#282828" color-link gutter-warning "#E6DB74,#282828" color-link cursor-line "#323232" color-link color-column "#323232" #No extended types; Plain brackets. color-link type.extended "default" #color-link symbol.brackets "default" color-link symbol.tag "#AE81FF,#282828" color-link match-brace "#282828,#AE81FF" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/colorschemes/monokai-dark.micro0000664000175000017510000000171015125206537024022 0ustar nileshnileshcolor-link default "#D5D8D6,#1D0000" color-link comment "#75715E" color-link identifier "#66D9EF" color-link constant "#AE81FF" color-link constant.string "#E6DB74" color-link constant.string.char "#BDE6AD" color-link statement "#F92672" color-link preproc "#CB4B16" color-link type "#66D9EF" color-link special "#A6E22E" color-link underlined "#D33682" color-link error "bold #CB4B16" color-link todo "bold #D33682" color-link hlsearch "#1D0000,#E6DB74" color-link statusline "#282828,#F8F8F2" color-link indent-char "#505050,#282828" color-link line-number "#AAAAAA,#282828" color-link current-line-number "#AAAAAA,#1D0000" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error "#CB4B16" color-link gutter-warning "#E6DB74" color-link cursor-line "#323232" color-link color-column "#323232" color-link match-brace "#1D0000,#AE81FF" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/colorschemes/material-tc.micro0000664000175000017510000000261315125206537023653 0ustar nileshnileshcolor-link color-column "#263238" color-link comment "#4F6875,#263238" color-link constant "#F07178,#263238" color-link constant.number "#F78C6A,#263238" color-link constant.specialChar "#89DDF3,#263238" color-link constant.string "#C3E88D,#263238" color-link current-line-number "#80DEEA,#263238" color-link cursor-line "#283942" color-link default "#EEFFFF,#263238" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link divider "#263238,#80DEEA" color-link error "bold #263238,#F07178" color-link gutter-error "#EEFFFF,#F07178" color-link gutter-warning "#EEFFFF,#FFF176" color-link hlsearch "#FFFFFF,#546E7A" color-link identifier "#82AAFF,#263238" color-link identifier.macro "#FFCB6B,#263238" color-link indent-char "#505050,#263238" color-link line-number "#656866,#283942" color-link preproc "#C792EA,#263238" color-link scrollbar "#80DEEA,#283942" color-link special "#C792EA,#263238" color-link statement "#C792EA,#263238" color-link statusline "#80DEEA,#3b4d56" color-link symbol "#96CBFE,#263238" color-link symbol.brackets "#89DDF3,#263238" color-link symbol.operator "#C792EA,#263238" color-link tabbar "#80DEEA,#3b4d56" color-link todo "bold #C792EA,#263238" color-link type "#FFCB6B,#263238" color-link underlined "underline #EEFFFF,#263238" color-link match-brace "#263238,#C792EA" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/colorschemes/gruvbox.micro0000664000175000017510000000143515125206537023146 0ustar nileshnileshcolor-link default "223,235" color-link comment "243,235" color-link constant "175,235" color-link constant.string "142,235" color-link identifier "109,235" color-link statement "124,235" color-link symbol "124,235" color-link preproc "72,235" color-link type "214,235" color-link special "172,235" color-link underlined "underline 109,235" color-link error "235,124" color-link todo "bold 223,235" color-link hlsearch "235,214" color-link diff-added "34" color-link diff-modified "214" color-link diff-deleted "160" color-link line-number "243,237" color-link current-line-number "172,235" color-link cursor-line "237" color-link color-column "237" color-link statusline "223,237" color-link tabbar "223,237" color-link match-brace "235,72" color-link tab-error "167" color-link trailingws "167" zyedidia-micro-6a62575/runtime/colorschemes/gruvbox-tc.micro0000664000175000017510000000213015125206537023543 0ustar nileshnileshcolor-link default "#ebdbb2,#282828" color-link comment "#928374,#282828" color-link symbol "#d79921,#282828" color-link constant "#d3869b,#282828" color-link constant.string "#b8bb26,#282828" color-link constant.string.char "#b8bb26,#282828" color-link identifier "#8ec07c,#282828" color-link statement "#fb4934,#282828" color-link preproc "#fb4934,235" color-link type "#fb4934,#282828" color-link special "#d79921,#282828" color-link underlined "underline #458588,#282828" color-link error "#9d0006,#282828" color-link todo "bold #ebdbb2,#282828" color-link hlsearch "#282828,#fabd2f" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error "#fb4934,#282828" color-link gutter-warning "#d79921,#282828" color-link line-number "#665c54,#3c3836" color-link current-line-number "#d79921,#282828" color-link cursor-line "#3c3836" color-link color-column "#79740e" color-link statusline "#ebdbb2,#665c54" color-link tabbar "#ebdbb2,#665c54" color-link match-brace "#282828,#d3869b" color-link tab-error "#d75f5f" color-link trailingws "#d75f5f" zyedidia-micro-6a62575/runtime/colorschemes/gotham.micro0000664000175000017510000000213415125206537022726 0ustar nileshnileshcolor-link default "#99D1CE,#0C1014" color-link comment "#245361,#0C1014" color-link identifier "#599CAB,#0C1014" color-link constant "#D26937,#0C1014" color-link constant.string "#2AA889,#0C1014" color-link constant.string.char "#D3EBE9,#0C1014" color-link statement "#599CAB,#0C1014" color-link preproc "#C23127,#0C1014" color-link type "#D26937,#0C1014" color-link special "#D26937,#0C1014" color-link underlined "#EDB443,#0C1014" color-link error "bold #C23127,#0C1014" color-link todo "bold #888CA6,#0C1014" color-link hlsearch "#091F2E,#EDB443" color-link statusline "#091F2E,#599CAB" color-link indent-char "#505050,#0C1014" color-link line-number "#245361,#11151C" color-link current-line-number "#599CAB,#11151C" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error "#C23127,#11151C" color-link gutter-warning "#EDB443,#11151C" color-link cursor-line "#091F2E" color-link color-column "#11151C" color-link symbol "#99D1CE,#0C1014" color-link match-brace "#0C1014,#D26937" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/colorschemes/geany.micro0000664000175000017510000000156615125206537022562 0ustar nileshnilesh#Geany color-link comment "red" color-link constant "default" color-link constant.string "bold yellow" color-link identifier "default" color-link preproc "cyan" color-link special "blue" color-link statement "blue" color-link symbol "default" color-link symbol.tag "bold blue" color-link type "blue" color-link type.extended "default" color-link error "red" color-link todo "bold cyan" color-link hlsearch "black,brightcyan" color-link indent-char "bold black" color-link line-number "" color-link current-line-number "" color-link statusline "black,white" color-link tabbar "black,white" color-link color-column "bold geren" color-link diff-added "green" color-link diff-modified "yellow" color-link diff-deleted "red" color-link gutter-error ",red" color-link gutter-warning "red" color-link match-brace "black,cyan" color-link tab-error "brightred" color-link trailingws "brightred" zyedidia-micro-6a62575/runtime/colorschemes/dukeubuntu-tc.micro0000664000175000017510000000300515125206537024244 0ustar nileshnileshcolor-link color-column "#2d0023" color-link comment "#886484,#2d0023" color-link constant.bool "#fd971f,#2d0023" color-link constant "#fd971f,#2d0023" color-link constant.string "#a0f000,#2d0023" color-link constant.string.char "#a0f000,#2d0023" color-link constant.string.url "#a0f000,#2d0023" color-link current-line-number "bold #fd971f,#2d0023" color-link cursor-line "#230019" color-link default "#ffffff,#2d0023" color-link diff-added "#00c8a0,#2d0023" color-link diff-modified "#fd971f,#2d0023" color-link diff-deleted "#cb4b16,#2d0023" color-link divider "#2d0023,#d0d0d0" color-link error "#cb4b16,#2d0023" color-link gutter-error "#cb4b16,#2d0023" color-link gutter-warning "#fce94f,#2d0023" color-link hlsearch "#ffffff,#005028" color-link identifier "#00c8a0,#2d0023" color-link identifier.class "#00c8a0,#2d0023" color-link indent-char "#a0a0a0,#2d0023" color-link line-number "#a0a0a0,#230019" color-link preproc "bold #5aaae6,#2d0023" color-link special "#a6e22e,#2d0023" color-link statement "bold #5aaae6,#2d0023" color-link statusline "#ffffff,#0078c8" color-link symbol "#00c8a0,#2d0023" color-link symbol.brackets "#ffffff,#2d0023" color-link symbol.tag "bold #5aaae6,#2d0023" color-link tabbar "#2d0023,#ffffff" color-link todo "#fce94f,#2d0023" color-link type "bold #3cc83c,#2d0023" color-link type.keyword "bold #5aaae6,#2d0023" color-link type.extended "#ffffff,#2d0023" color-link underlined "#886484,#2d0023" color-link match-brace "#2d0023,#5aaae6" color-link tab-error "#d75f5f" color-link trailingws "#d75f5f" zyedidia-micro-6a62575/runtime/colorschemes/dukelight-tc.micro0000664000175000017510000000303115125206537024030 0ustar nileshnileshcolor-link color-column "#f0f0f0" color-link comment "#3f7f5f,#f0f0f0" color-link constant.bool "#641e00,#f0f0f0" color-link constant "#641e00,#f0f0f0" color-link constant.string "#0000ff,#f0f0f0" color-link constant.string.char "#0000ff,#f0f0f0" color-link constant.string.url "#0000ff,#f0f0f0" color-link current-line-number "bold #004080,#f0f0f0" color-link cursor-line "#e6e6e6" color-link default "#000000,#f0f0f0" color-link diff-added "#008040,#f0f0f0" color-link diff-modified "#641e00,#f0f0f0" color-link diff-deleted "#500000,#f0f0f0" color-link divider "#f0f0f0,#004080" color-link error "#500000,#f0f0f0" color-link gutter-error "#500000,#f0f0f0" color-link gutter-warning "#dcc800,#f0f0f0" color-link hlsearch "#000000,#b8d8e8" color-link identifier "bold #0078a0,#f0f0f0" color-link identifier.class "bold #0078a0,#f0f0f0" color-link indent-char "#404040,#f0f0f0" color-link line-number "#404040,#e6e6e6" color-link preproc "bold #780050,#f0f0f0" color-link special "bold #0078a0,#f0f0f0" color-link statement "bold #780050,#f0f0f0" color-link statusline "#ffffff,#0078c8" color-link symbol "bold #0078a0,#f0f0f0" color-link symbol.brackets "#000000,#f0f0f0" color-link symbol.tag "bold #780050,#f0f0f0" color-link tabbar "#f0f0f0,#004080" color-link todo "#dcc800,#f0f0f0" color-link type "bold #004080,#f0f0f0" color-link type.keyword "bold #780050,#f0f0f0" color-link type.extended "#000000,#f0f0f0" color-link underlined "#3f7f5f,#f0f0f0" color-link match-brace "#f0f0f0,#780050" color-link tab-error "#ff8787" color-link trailingws "#ff8787" zyedidia-micro-6a62575/runtime/colorschemes/dukedark-tc.micro0000664000175000017510000000300515125206537023643 0ustar nileshnileshcolor-link color-column "#001e28" color-link comment "#608b4e,#001e28" color-link constant.bool "#fd971f,#001e28" color-link constant "#fd971f,#001e28" color-link constant.string "#a0f000,#001e28" color-link constant.string.char "#a0f000,#001e28" color-link constant.string.url "#a0f000,#001e28" color-link current-line-number "bold #fd971f,#001e28" color-link cursor-line "#001923" color-link default "#ffffff,#001e28" color-link diff-added "#00c8a0,#001e28" color-link diff-modified "#fd971f,#001e28" color-link diff-deleted "#cb4b16,#001e28" color-link divider "#001e28,#d0d0d0" color-link error "#cb4b16,#001e28" color-link gutter-error "#cb4b16,#001e28" color-link gutter-warning "#fce94f,#001e28" color-link hlsearch "#ffffff,#005028" color-link identifier "#00c8a0,#001e28" color-link identifier.class "#00c8a0,#001e28" color-link indent-char "#a0a0a0,#001e28" color-link line-number "#a0a0a0,#001923" color-link preproc "bold #5aaae6,#001e28" color-link special "#a6e22e,#001e28" color-link statement "bold #5aaae6,#001e28" color-link statusline "#ffffff,#0078c8" color-link symbol "#00c8a0,#001e28" color-link symbol.brackets "#ffffff,#001e28" color-link symbol.tag "bold #5aaae6,#001e28" color-link tabbar "#001e28,#ffffff" color-link todo "#fce94f,#001e28" color-link type "bold #3cc83c,#001e28" color-link type.keyword "bold #5aaae6,#001e28" color-link type.extended "#ffffff,#001e28" color-link underlined "#608b4e,#001e28" color-link match-brace "#001e28,#5aaae6" color-link tab-error "#d75f5f" color-link trailingws "#d75f5f" zyedidia-micro-6a62575/runtime/colorschemes/dracula-tc.micro0000664000175000017510000000233315125206537023467 0ustar nileshnileshcolor-link default "#F8F8F2,#282A36" color-link comment "#6272A4" color-link identifier "#50FA7B" color-link identifier.class "#8BE9FD" color-link identifier.var "#F8F8F2" color-link constant "#BD93F9" color-link constant.number "#F8F8F2" color-link constant.string "#F1FA8C" color-link symbol "#FF79C6" color-link symbol.brackets "#F8F8F2" color-link symbol.tag "#AE81FF" color-link type "italic #8BE9FD" color-link type.keyword "#FF79C6" color-link special "#FF79C6" color-link statement "#FF79C6" color-link preproc "#FF79C6" color-link underlined "#FF79C6" color-link error "bold #FF5555" color-link todo "bold #FF79C6" color-link hlsearch "#282A36,#50FA7B" color-link diff-added "#50FA7B" color-link diff-modified "#FFB86C" color-link diff-deleted "#FF5555" color-link gutter-error "#FF5555" color-link gutter-warning "#E6DB74" color-link statusline "#282A36,#F8F8F2" color-link tabbar "#282A36,#F8F8F2" color-link indent-char "#6272A4" color-link line-number "#6272A4" color-link current-line-number "#F8F8F2" color-link cursor-line "#44475A,#F8F8F2" color-link color-column "#44475A" color-link type.extended "default" color-link match-brace "#282A36,#FF79C6" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/colorschemes/default.micro0000664000175000017510000000002215125206537023065 0ustar nileshnileshinclude "monokai" zyedidia-micro-6a62575/runtime/colorschemes/darcula.micro0000664000175000017510000000242515125206537023065 0ustar nileshnileshcolor-link default "#CCCCCC,#242424" color-link comment "#707070,#242424" color-link identifier "#FFC66D,#242424" color-link constant "#7A9EC2,#242424" color-link constant.string "#6A8759,#242424" color-link constant.string.char "#6A8759,#242424" color-link statement "#CC8242,#242424" color-link symbol "#CCCCCC,#242424" color-link preproc "#CC8242,#242424" color-link type "#CC8242,#242424" color-link special "#CC8242,#242424" color-link underlined "#D33682,#242424" color-link error "bold #CB4B16,#242424" color-link todo "bold #D33682,#242424" color-link hlsearch "#CCCCCC,#32593D" color-link statusline "#242424,#CCCCCC" color-link tabbar "#242424,#CCCCCC" color-link indent-char "#4F4F4F,#242424" color-link line-number "#666666,#2C2C2C" color-link current-line-number "#666666,#242424" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error "#CB4B16,#242424" color-link gutter-warning "#E6DB74,#242424" color-link cursor-line "#2C2C2C" color-link color-column "#2C2C2C" #No extended types; Plain brackets. color-link type.extended "default" #color-link symbol.brackets "default" color-link symbol.tag "#AE81FF,#242424" color-link match-brace "#242424,#7A9EC2" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/colorschemes/cmc-tc.micro0000664000175000017510000000307515125206537022622 0ustar nileshnilesh#CaptainMcClellan's personal colour scheme. #Full colour edition. color-link default "#aaaaaa,#1e2124" color-link comment "bold #555555" color-link constant "#008888" #color-link constant.string "#888800" color-link constant.string "#a85700" color-link constant.specialChar "bold #ccccff" color-link identifier "bold #e34234" color-link identifier.macro "bold #e34234" color-link identifier.var "bold #5757ff" color-link identifier.class "bold #ffffff" color-link statement "bold #ffff55" color-link symbol "#722f37" color-link symbol.brackets "#4169e1" color-link symbol.tag "#5757ff" color-link preproc "bold #55ffff" color-link type "#3eb489" color-link type.keyword "bold #bdecb6" color-link special "#b57edc" color-link ignore "default" color-link error "bold ,#e34234" color-link todo "bold underline #888888,#f26522" color-link hlsearch "#b7b7b7,#32593d" color-link indent-char ",#bdecb6" color-link line-number "#bdecb6,#36393e" color-link line-number.scrollbar "#3eb489" color-link statusline "#aaaaaa,#8a496b" color-link tabbar "#aaaaaa,#8a496b" color-link current-line-number "bold #e34234,#424549" color-link current-line-number.scroller "red" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error ",#e34234" color-link gutter-warning "#e34234" color-link color-column "#f26522" color-link constant.bool "bold #55ffff" color-link constant.bool.true "bold #85ff85" color-link constant.bool.false "bold #ff8585" color-link match-brace "#1e2124,#55ffff" color-link tab-error "#d75f5f" color-link trailingws "#d75f5f" zyedidia-micro-6a62575/runtime/colorschemes/cmc-16.micro0000664000175000017510000000322015125206537022432 0ustar nileshnilesh#CaptainMcClellan's personal color scheme. #16 colour version. color-link comment "bold black" color-link constant "cyan" color-link constant.bool "bold cyan" color-link constant.bool.true "bold green" color-link constant.bool.false "bold red" color-link constant.string "yellow" color-link constant.string.url "underline blue, white" #color-link constant.number "constant" color-link constant.specialChar "bold magenta" color-link identifier "bold red" color-link identifier.macro "bold red" color-link identifier.var "bold blue" #color-link identifier.class "bold green" color-link identifier.class "bold white" color-link statement "bold yellow" color-link symbol "red" color-link symbol.brackets "blue" color-link symbol.tag "bold blue" color-link symbol.tag.extended "bold green" color-link preproc "bold cyan" color-link type "green" color-link type.keyword "bold green" color-link special "magenta" color-link ignore "default" color-link error "bold ,brightred" color-link todo "underline black,brightyellow" color-link hlsearch "white,darkgreen" color-link indent-char ",brightgreen" color-link line-number "green" color-link line-number.scrollbar "green" color-link statusline "white,blue" color-link tabbar "white,blue" color-link current-line-number "red" color-link current-line-number.scroller "red" color-link diff-added "green" color-link diff-modified "yellow" color-link diff-deleted "red" color-link gutter-error ",red" color-link gutter-warning "red" color-link color-column "cyan" color-link underlined.url "underline blue, white" color-link divider "blue" color-link match-brace "black,cyan" color-link tab-error "brightred" color-link trailingws "brightred" zyedidia-micro-6a62575/runtime/colorschemes/bubblegum.micro0000664000175000017510000000172715125206537023422 0ustar nileshnileshcolor-link default "241,231" color-link comment "246,231" color-link constant "130,231" color-link constant.string "136,231" color-link constant.number "131,231" color-link identifier "133,231" color-link statement "32,231" color-link symbol "32,231" color-link preproc "28,231" color-link type "61,231" color-link special "167,231" color-link error "231, 160" color-link underlined "underline 241,231" color-link todo "246,231" color-link hlsearch "231,136" color-link statusline "241,254" color-link tabbar "241,254" color-link diff-added "34" color-link diff-modified "214" color-link diff-deleted "160" color-link gutter-error "197,231" color-link gutter-warning "134,231" color-link line-number "246,254" color-link cursor-line "254" color-link color-column "254" #No extended types (bool in C, &c.) and plain brackets color-link type.extended "241,231" color-link symbol.brackets "241,231" color-link match-brace "231,28" color-link tab-error "210" color-link trailingws "210" zyedidia-micro-6a62575/runtime/colorschemes/atom-dark.micro0000664000175000017510000000232515125206537023330 0ustar nileshnileshcolor-link default "#C5C8C6,#1D1F21" color-link comment "#7C7C7C,#1D1F21" color-link identifier "#F9EE98,#1D1F21" color-link constant "#FF73FD,#1D1F21" color-link constant.string "#A8FF60,#1D1F21" color-link statement "#96CBFE,#1D1F21" color-link symbol "#96CBFE,#1D1F21" color-link preproc "#62B1FE,#1D1F21" color-link type "#C6C5FE,#1D1F21" color-link special "#A6E22E,#1D1F21" color-link underlined "#D33682,#1D1F21" color-link error "bold #FF4444,#1D1F21" color-link todo "bold #FF8844,#1D1F21" color-link hlsearch "#000000,#B4EC85" color-link statusline "#1D1F21,#C5C8C6" color-link tabbar "#1D1F21,#C5C8C6" color-link indent-char "#505050,#1D1F21" color-link line-number "#656866,#232526" color-link current-line-number "#656866,#1D1F21" color-link diff-added "#00AF00" color-link diff-modified "#FFAF00" color-link diff-deleted "#D70000" color-link gutter-error "#FF4444,#1D1F21" color-link gutter-warning "#EEEE77,#1D1F21" color-link cursor-line "#2D2F31" color-link color-column "#2D2F31" #color-link symbol.brackets "#96CBFE,#1D1F21" #No extended types (bool in C, etc.) #color-link type.extended "default" #Plain brackets color-link match-brace "#1D1F21,#62B1FE" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" zyedidia-micro-6a62575/runtime/README.md0000664000175000017510000000046315125206537017210 0ustar nileshnilesh# Runtime files for Micro This directory will be embedded in the Go binary for portability, but it may just as well be put in `~/.config/micro`. If you would like to make your own colorschemes and syntax files, you can put them in `~/.config/micro/colorschemes` and `~/.config/micro/syntax` respectively. zyedidia-micro-6a62575/pkg/0000775000175000017510000000000015125206537015024 5ustar nileshnileshzyedidia-micro-6a62575/pkg/highlight/0000775000175000017510000000000015125206537016773 5ustar nileshnileshzyedidia-micro-6a62575/pkg/highlight/unicode.go0000664000175000017510000000312115125206537020745 0ustar nileshnileshpackage highlight import ( "unicode" "unicode/utf8" ) var minMark = rune(unicode.Mark.R16[0].Lo) func isMark(r rune) bool { // Fast path if r < minMark { return false } return unicode.In(r, unicode.Mark) } // DecodeCharacter returns the next character from an array of bytes // A character is a rune along with any accompanying combining runes func DecodeCharacter(b []byte) (rune, []rune, int) { r, size := utf8.DecodeRune(b) b = b[size:] c, s := utf8.DecodeRune(b) var combc []rune for isMark(c) { combc = append(combc, c) size += s b = b[s:] c, s = utf8.DecodeRune(b) } return r, combc, size } // DecodeCharacterInString returns the next character from a string // A character is a rune along with any accompanying combining runes func DecodeCharacterInString(str string) (rune, []rune, int) { r, size := utf8.DecodeRuneInString(str) str = str[size:] c, s := utf8.DecodeRuneInString(str) var combc []rune for isMark(c) { combc = append(combc, c) size += s str = str[s:] c, s = utf8.DecodeRuneInString(str) } return r, combc, size } // CharacterCount returns the number of characters in a byte array // Similar to utf8.RuneCount but for unicode characters func CharacterCount(b []byte) int { s := 0 for len(b) > 0 { r, size := utf8.DecodeRune(b) if !isMark(r) { s++ } b = b[size:] } return s } // CharacterCount returns the number of characters in a string // Similar to utf8.RuneCountInString but for unicode characters func CharacterCountInString(str string) int { s := 0 for _, r := range str { if !isMark(r) { s++ } } return s } zyedidia-micro-6a62575/pkg/highlight/parser.go0000664000175000017510000002611115125206537020617 0ustar nileshnileshpackage highlight import ( "bytes" "errors" "fmt" "regexp" "gopkg.in/yaml.v2" ) // A Group represents a syntax group type Group uint8 // Groups contains all of the groups that are defined // You can access them in the map via their string name var Groups map[string]Group var numGroups Group // String returns the group name attached to the specific group func (g Group) String() string { for k, v := range Groups { if v == g { return k } } return "" } // A Def is a full syntax definition for a language // It has a filetype, information about how to detect the filetype based // on filename or header (the first line of the file) // Then it has the rules which define how to highlight the file type Def struct { *Header rules *rules } type Header struct { FileType string FileNameRegex *regexp.Regexp HeaderRegex *regexp.Regexp SignatureRegex *regexp.Regexp } type HeaderYaml struct { FileType string `yaml:"filetype"` Detect struct { FNameRegexStr string `yaml:"filename"` HeaderRegexStr string `yaml:"header"` SignatureRegexStr string `yaml:"signature"` } `yaml:"detect"` } type File struct { FileType string yamlSrc map[any]any } // A Pattern is one simple syntax rule // It has a group that the rule belongs to, as well as // the regular expression to match the pattern type pattern struct { group Group regex *regexp.Regexp } // rules defines which patterns and regions can be used to highlight // a filetype type rules struct { regions []*region patterns []*pattern includes []string } // A region is a highlighted region (such as a multiline comment, or a string) // It belongs to a group, and has start and end regular expressions // A region also has rules of its own that only apply when matching inside the // region and also rules from the above region do not match inside this region // Note that a region may contain more regions type region struct { group Group limitGroup Group parent *region start *regexp.Regexp end *regexp.Regexp skip *regexp.Regexp rules *rules } func init() { Groups = make(map[string]Group) } // MakeHeader takes a header (.hdr file) file and parses the header // Header files make parsing more efficient when you only want to compute // on the headers of syntax files // A yaml file might take ~400us to parse while a header file only takes ~20us func MakeHeader(data []byte) (*Header, error) { lines := bytes.Split(data, []byte{'\n'}) if len(lines) < 4 { return nil, errors.New("Header file has incorrect format") } header := new(Header) var err error header.FileType = string(lines[0]) fnameRegexStr := string(lines[1]) headerRegexStr := string(lines[2]) signatureRegexStr := string(lines[3]) if fnameRegexStr != "" { header.FileNameRegex, err = regexp.Compile(fnameRegexStr) } if err == nil && headerRegexStr != "" { header.HeaderRegex, err = regexp.Compile(headerRegexStr) } if err == nil && signatureRegexStr != "" { header.SignatureRegex, err = regexp.Compile(signatureRegexStr) } if err != nil { return nil, err } return header, nil } // MakeHeaderYaml takes a yaml spec for a syntax file and parses the // header func MakeHeaderYaml(data []byte) (*Header, error) { var hdrYaml HeaderYaml err := yaml.Unmarshal(data, &hdrYaml) if err != nil { return nil, err } header := new(Header) header.FileType = hdrYaml.FileType if hdrYaml.Detect.FNameRegexStr != "" { header.FileNameRegex, err = regexp.Compile(hdrYaml.Detect.FNameRegexStr) } if err == nil && hdrYaml.Detect.HeaderRegexStr != "" { header.HeaderRegex, err = regexp.Compile(hdrYaml.Detect.HeaderRegexStr) } if err == nil && hdrYaml.Detect.SignatureRegexStr != "" { header.SignatureRegex, err = regexp.Compile(hdrYaml.Detect.SignatureRegexStr) } if err != nil { return nil, err } return header, nil } // MatchFileName will check the given file name with the stored regex func (header *Header) MatchFileName(filename string) bool { if header.FileNameRegex != nil { return header.FileNameRegex.MatchString(filename) } return false } func (header *Header) MatchFileHeader(firstLine []byte) bool { if header.HeaderRegex != nil { return header.HeaderRegex.Match(firstLine) } return false } // HasFileSignature checks the presence of a stored signature func (header *Header) HasFileSignature() bool { return header.SignatureRegex != nil } // MatchFileSignature will check the given line with the stored regex func (header *Header) MatchFileSignature(line []byte) bool { if header.SignatureRegex != nil { return header.SignatureRegex.Match(line) } return false } func ParseFile(input []byte) (f *File, err error) { // This is just so if we have an error, we can exit cleanly and return the parse error to the user defer func() { if r := recover(); r != nil { var ok bool err, ok = r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } } }() var rules map[any]any if err = yaml.Unmarshal(input, &rules); err != nil { return nil, err } f = new(File) f.yamlSrc = rules for k, v := range rules { if k == "filetype" { filetype := v.(string) if filetype == "" { return nil, errors.New("empty filetype") } f.FileType = filetype break } } if f.FileType == "" { return nil, errors.New("missing filetype") } return f, err } // ParseDef parses an input syntax file into a highlight Def func ParseDef(f *File, header *Header) (s *Def, err error) { // This is just so if we have an error, we can exit cleanly and return the parse error to the user defer func() { if r := recover(); r != nil { var ok bool err, ok = r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } } }() src := f.yamlSrc s = new(Def) s.Header = header for k, v := range src { if k == "rules" { inputRules := v.([]any) rules, err := parseRules(inputRules, nil) if err != nil { return nil, err } s.rules = rules } } if s.rules == nil { // allow empty rules s.rules = &rules{} } return s, err } // HasIncludes returns whether this syntax def has any include statements func HasIncludes(d *Def) bool { hasIncludes := len(d.rules.includes) > 0 for _, r := range d.rules.regions { hasIncludes = hasIncludes || hasIncludesInRegion(r) } return hasIncludes } func hasIncludesInRegion(region *region) bool { hasIncludes := len(region.rules.includes) > 0 for _, r := range region.rules.regions { hasIncludes = hasIncludes || hasIncludesInRegion(r) } return hasIncludes } // GetIncludes returns a list of filetypes that are included by this syntax def func GetIncludes(d *Def) []string { includes := d.rules.includes for _, r := range d.rules.regions { includes = append(includes, getIncludesInRegion(r)...) } return includes } func getIncludesInRegion(region *region) []string { includes := region.rules.includes for _, r := range region.rules.regions { includes = append(includes, getIncludesInRegion(r)...) } return includes } // ResolveIncludes will sort out the rules for including other filetypes // You should call this after parsing all the Defs func ResolveIncludes(def *Def, files []*File) { resolveIncludesInDef(files, def) } func resolveIncludesInDef(files []*File, d *Def) { for _, lang := range d.rules.includes { for _, searchFile := range files { if lang == searchFile.FileType { searchDef, _ := ParseDef(searchFile, nil) d.rules.patterns = append(d.rules.patterns, searchDef.rules.patterns...) d.rules.regions = append(d.rules.regions, searchDef.rules.regions...) } } } for _, r := range d.rules.regions { resolveIncludesInRegion(files, r) r.parent = nil } } func resolveIncludesInRegion(files []*File, region *region) { for _, lang := range region.rules.includes { for _, searchFile := range files { if lang == searchFile.FileType { searchDef, _ := ParseDef(searchFile, nil) region.rules.patterns = append(region.rules.patterns, searchDef.rules.patterns...) region.rules.regions = append(region.rules.regions, searchDef.rules.regions...) } } } for _, r := range region.rules.regions { resolveIncludesInRegion(files, r) r.parent = region } } func parseRules(input []any, curRegion *region) (ru *rules, err error) { defer func() { if r := recover(); r != nil { var ok bool err, ok = r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } } }() ru = new(rules) for _, v := range input { rule := v.(map[any]any) for k, val := range rule { group := k switch object := val.(type) { case string: if object == "" { return nil, fmt.Errorf("Empty rule %s", k) } if k == "include" { ru.includes = append(ru.includes, object) } else { // Pattern r, err := regexp.Compile(object) if err != nil { return nil, err } groupStr := group.(string) if _, ok := Groups[groupStr]; !ok { numGroups++ Groups[groupStr] = numGroups } groupNum := Groups[groupStr] ru.patterns = append(ru.patterns, &pattern{groupNum, r}) } case map[any]any: // region region, err := parseRegion(group.(string), object, curRegion) if err != nil { return nil, err } ru.regions = append(ru.regions, region) default: return nil, fmt.Errorf("Bad type %T", object) } } } return ru, nil } func parseRegion(group string, regionInfo map[any]any, prevRegion *region) (r *region, err error) { defer func() { if r := recover(); r != nil { var ok bool err, ok = r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } } }() r = new(region) if _, ok := Groups[group]; !ok { numGroups++ Groups[group] = numGroups } groupNum := Groups[group] r.group = groupNum r.parent = prevRegion // start is mandatory if start, ok := regionInfo["start"]; ok { start := start.(string) if start == "" { return nil, fmt.Errorf("Empty start in %s", group) } r.start, err = regexp.Compile(start) if err != nil { return nil, err } } else { return nil, fmt.Errorf("Missing start in %s", group) } // end is mandatory if end, ok := regionInfo["end"]; ok { end := end.(string) if end == "" { return nil, fmt.Errorf("Empty end in %s", group) } r.end, err = regexp.Compile(end) if err != nil { return nil, err } } else { return nil, fmt.Errorf("Missing end in %s", group) } // skip is optional if skip, ok := regionInfo["skip"]; ok { skip := skip.(string) if skip == "" { return nil, fmt.Errorf("Empty skip in %s", group) } r.skip, err = regexp.Compile(skip) if err != nil { return nil, err } } // limit-color is optional if groupStr, ok := regionInfo["limit-group"]; ok { groupStr := groupStr.(string) if groupStr == "" { return nil, fmt.Errorf("Empty limit-group in %s", group) } if _, ok := Groups[groupStr]; !ok { numGroups++ Groups[groupStr] = numGroups } groupNum := Groups[groupStr] r.limitGroup = groupNum if err != nil { return nil, err } } else { r.limitGroup = r.group } // rules are optional if rules, ok := regionInfo["rules"]; ok { r.rules, err = parseRules(rules.([]any), r) if err != nil { return nil, err } } if r.rules == nil { // allow empty rules r.rules = &rules{} } return r, nil } zyedidia-micro-6a62575/pkg/highlight/highlighter.go0000664000175000017510000002355215125206537021627 0ustar nileshnileshpackage highlight import ( "regexp" "strings" ) func sliceStart(slc []byte, index int) []byte { len := len(slc) i := 0 totalSize := 0 for totalSize < len { if i >= index { return slc[totalSize:] } _, _, size := DecodeCharacter(slc[totalSize:]) totalSize += size i++ } return slc[totalSize:] } func sliceEnd(slc []byte, index int) []byte { len := len(slc) i := 0 totalSize := 0 for totalSize < len { if i >= index { return slc[:totalSize] } _, _, size := DecodeCharacter(slc[totalSize:]) totalSize += size i++ } return slc[:totalSize] } // RunePos returns the rune index of a given byte index // This could cause problems if the byte index is between code points func runePos(p int, str []byte) int { if p < 0 { return 0 } if p >= len(str) { return CharacterCount(str) } return CharacterCount(str[:p]) } // A State represents the region at the end of a line type State *region // LineStates is an interface for a buffer-like object which can also store the states and matches for every line type LineStates interface { LineBytes(n int) []byte LinesNum() int State(lineN int) State SetState(lineN int, s State) SetMatch(lineN int, m LineMatch) Lock() Unlock() } // A Highlighter contains the information needed to highlight a string type Highlighter struct { lastRegion *region Def *Def } // NewHighlighter returns a new highlighter from the given syntax definition func NewHighlighter(def *Def) *Highlighter { h := new(Highlighter) h.Def = def return h } // LineMatch represents the syntax highlighting matches for one line. Each index where the coloring is changed is marked with that // color's group (represented as one byte) type LineMatch map[int]Group func findIndex(regex *regexp.Regexp, skip *regexp.Regexp, str []byte) []int { var strbytes []byte if skip != nil { strbytes = skip.ReplaceAllFunc(str, func(match []byte) []byte { res := make([]byte, CharacterCount(match)) return res }) } else { strbytes = str } match := regex.FindIndex(strbytes) if match == nil { return nil } // return []int{match.Index, match.Index + match.Length} return []int{runePos(match[0], str), runePos(match[1], str)} } func findAllIndex(regex *regexp.Regexp, str []byte) [][]int { matches := regex.FindAllIndex(str, -1) for i, m := range matches { matches[i][0] = runePos(m[0], str) matches[i][1] = runePos(m[1], str) } return matches } func (h *Highlighter) highlightRegion(highlights LineMatch, start int, canMatchEnd bool, lineNum int, line []byte, curRegion *region, statesOnly bool) LineMatch { lineLen := CharacterCount(line) if start == 0 { if !statesOnly { if _, ok := highlights[0]; !ok { highlights[0] = curRegion.group } } } var firstRegion *region firstLoc := []int{lineLen, 0} searchNesting := true endLoc := findIndex(curRegion.end, curRegion.skip, line) if endLoc != nil { if start == endLoc[0] { searchNesting = false } else { firstLoc = endLoc } } if searchNesting { for _, r := range curRegion.rules.regions { loc := findIndex(r.start, r.skip, line) if loc != nil { if loc[0] < firstLoc[0] { firstLoc = loc firstRegion = r } } } } if firstRegion != nil && firstLoc[0] != lineLen { if !statesOnly { highlights[start+firstLoc[0]] = firstRegion.limitGroup } h.highlightEmptyRegion(highlights, start+firstLoc[1], canMatchEnd, lineNum, sliceStart(line, firstLoc[1]), statesOnly) h.highlightRegion(highlights, start+firstLoc[1], canMatchEnd, lineNum, sliceStart(line, firstLoc[1]), firstRegion, statesOnly) return highlights } if !statesOnly { fullHighlights := make([]Group, lineLen) for i := 0; i < len(fullHighlights); i++ { fullHighlights[i] = curRegion.group } if searchNesting { for _, p := range curRegion.rules.patterns { if curRegion.group == curRegion.limitGroup || p.group == curRegion.limitGroup { matches := findAllIndex(p.regex, line) for _, m := range matches { if (endLoc == nil) || (m[0] < endLoc[0]) { for i := m[0]; i < m[1]; i++ { fullHighlights[i] = p.group } } } } } } for i, h := range fullHighlights { if i == 0 || h != fullHighlights[i-1] { highlights[start+i] = h } } } loc := endLoc if loc != nil { if !statesOnly { highlights[start+loc[0]] = curRegion.limitGroup } if curRegion.parent == nil { if !statesOnly { highlights[start+loc[1]] = 0 } h.highlightEmptyRegion(highlights, start+loc[1], canMatchEnd, lineNum, sliceStart(line, loc[1]), statesOnly) return highlights } if !statesOnly { highlights[start+loc[1]] = curRegion.parent.group } h.highlightRegion(highlights, start+loc[1], canMatchEnd, lineNum, sliceStart(line, loc[1]), curRegion.parent, statesOnly) return highlights } if canMatchEnd { h.lastRegion = curRegion } return highlights } func (h *Highlighter) highlightEmptyRegion(highlights LineMatch, start int, canMatchEnd bool, lineNum int, line []byte, statesOnly bool) LineMatch { lineLen := CharacterCount(line) if lineLen == 0 { if canMatchEnd { h.lastRegion = nil } return highlights } var firstRegion *region firstLoc := []int{lineLen, 0} for _, r := range h.Def.rules.regions { loc := findIndex(r.start, r.skip, line) if loc != nil { if loc[0] < firstLoc[0] { firstLoc = loc firstRegion = r } } } if firstRegion != nil && firstLoc[0] != lineLen { if !statesOnly { highlights[start+firstLoc[0]] = firstRegion.limitGroup } h.highlightEmptyRegion(highlights, start, false, lineNum, sliceEnd(line, firstLoc[0]), statesOnly) h.highlightRegion(highlights, start+firstLoc[1], canMatchEnd, lineNum, sliceStart(line, firstLoc[1]), firstRegion, statesOnly) return highlights } if statesOnly { if canMatchEnd { h.lastRegion = nil } return highlights } fullHighlights := make([]Group, len(line)) for _, p := range h.Def.rules.patterns { matches := findAllIndex(p.regex, line) for _, m := range matches { for i := m[0]; i < m[1]; i++ { fullHighlights[i] = p.group } } } for i, h := range fullHighlights { if i == 0 || h != fullHighlights[i-1] { // if _, ok := highlights[start+i]; !ok { highlights[start+i] = h // } } } if canMatchEnd { h.lastRegion = nil } return highlights } // HighlightString syntax highlights a string // Use this function for simple syntax highlighting and use the other functions for // more advanced syntax highlighting. They are optimized for quick rehighlighting of the same // text with minor changes made func (h *Highlighter) HighlightString(input string) []LineMatch { lines := strings.Split(input, "\n") var lineMatches []LineMatch for i := 0; i < len(lines); i++ { line := []byte(lines[i]) highlights := make(LineMatch) if i == 0 || h.lastRegion == nil { lineMatches = append(lineMatches, h.highlightEmptyRegion(highlights, 0, true, i, line, false)) } else { lineMatches = append(lineMatches, h.highlightRegion(highlights, 0, true, i, line, h.lastRegion, false)) } } return lineMatches } // HighlightStates correctly sets all states for the buffer func (h *Highlighter) HighlightStates(input LineStates) { for i := 0; ; i++ { input.Lock() if i >= input.LinesNum() { input.Unlock() break } line := input.LineBytes(i) // highlights := make(LineMatch) if i == 0 || h.lastRegion == nil { h.highlightEmptyRegion(nil, 0, true, i, line, true) } else { h.highlightRegion(nil, 0, true, i, line, h.lastRegion, true) } curState := h.lastRegion input.SetState(i, curState) input.Unlock() } } // HighlightMatches sets the matches for each line from startline to endline // It sets all other matches in the buffer to nil to conserve memory // This assumes that all the states are set correctly func (h *Highlighter) HighlightMatches(input LineStates, startline, endline int) { for i := startline; i <= endline; i++ { input.Lock() if i >= input.LinesNum() { input.Unlock() break } line := input.LineBytes(i) highlights := make(LineMatch) var match LineMatch if i == 0 || input.State(i-1) == nil { match = h.highlightEmptyRegion(highlights, 0, true, i, line, false) } else { match = h.highlightRegion(highlights, 0, true, i, line, input.State(i-1), false) } input.SetMatch(i, match) input.Unlock() } } // ReHighlightStates will scan down from `startline` and set the appropriate end of line state // for each line until it comes across a line whose state does not change // returns the number of the final line func (h *Highlighter) ReHighlightStates(input LineStates, startline int) int { // lines := input.LineData() h.lastRegion = nil if startline > 0 { input.Lock() if startline-1 < input.LinesNum() { h.lastRegion = input.State(startline - 1) } input.Unlock() } for i := startline; ; i++ { input.Lock() if i >= input.LinesNum() { input.Unlock() break } line := input.LineBytes(i) // highlights := make(LineMatch) // var match LineMatch if i == 0 || h.lastRegion == nil { h.highlightEmptyRegion(nil, 0, true, i, line, true) } else { h.highlightRegion(nil, 0, true, i, line, h.lastRegion, true) } curState := h.lastRegion lastState := input.State(i) input.SetState(i, curState) input.Unlock() if curState == lastState { return i } } return input.LinesNum() - 1 } // ReHighlightLine will rehighlight the state and match for a single line func (h *Highlighter) ReHighlightLine(input LineStates, lineN int) { input.Lock() defer input.Unlock() line := input.LineBytes(lineN) highlights := make(LineMatch) h.lastRegion = nil if lineN > 0 { h.lastRegion = input.State(lineN - 1) } var match LineMatch if lineN == 0 || h.lastRegion == nil { match = h.highlightEmptyRegion(highlights, 0, true, lineN, line, false) } else { match = h.highlightRegion(highlights, 0, true, lineN, line, h.lastRegion, false) } curState := h.lastRegion input.SetMatch(lineN, match) input.SetState(lineN, curState) } zyedidia-micro-6a62575/internal/0000775000175000017510000000000015125206537016057 5ustar nileshnileshzyedidia-micro-6a62575/internal/views/0000775000175000017510000000000015125206537017214 5ustar nileshnileshzyedidia-micro-6a62575/internal/views/splits_test.go0000664000175000017510000000040015125206537022112 0ustar nileshnileshpackage views import ( "fmt" "testing" ) func TestHSplit(t *testing.T) { root := NewRoot(0, 0, 80, 80) n1 := root.VSplit(true) root.GetNode(n1).VSplit(true) root.GetNode(root.id).ResizeSplit(7) root.Resize(120, 120) fmt.Println(root.String()) } zyedidia-micro-6a62575/internal/views/splits.go0000664000175000017510000002762615125206537021076 0ustar nileshnileshpackage views import ( "fmt" "strings" ) type SplitType uint8 const ( STVert = 0 STHoriz = 1 STUndef = 2 ) var idcounter uint64 // NewID returns a new unique id func NewID() uint64 { idcounter++ return idcounter } // A View is a size and location of a split type View struct { X, Y int W, H int } // A Node describes a split in the tree // If a node is a leaf node then it corresponds to a buffer that is being // displayed otherwise it has a number of children of the opposite type // (vertical splits have horizontal children and vice versa) type Node struct { View Kind SplitType parent *Node children []*Node // Nodes can be marked as non resizable if they shouldn't be rescaled // when the terminal window is resized or when a new split is added // Only the splits on the edges of the screen can be marked as non resizable canResize bool // A node may also be marked with proportional scaling. This means that when // the window is resized the split maintains its proportions propScale bool // Defines the proportion of the screen this node should take up if propScale is // on propW, propH float64 // The id is unique for each leaf node and provides a way to keep track of a split // The id cannot be 0 id uint64 } // NewNode returns a new node with the given specifications func NewNode(Kind SplitType, x, y, w, h int, parent *Node, id uint64) *Node { n := new(Node) n.Kind = Kind n.canResize = true n.propScale = true n.X, n.Y, n.W, n.H = x, y, w, h n.children = make([]*Node, 0) n.parent = parent n.id = id if parent != nil { n.propW, n.propH = float64(w)/float64(parent.W), float64(h)/float64(parent.H) } else { n.propW, n.propH = 1, 1 } return n } // NewRoot returns an empty Node with a size and location // The type of the node will be determined by the first action on the node // In other words, a lone split is neither horizontal nor vertical, it only // becomes one or the other after a vsplit or hsplit is made func NewRoot(x, y, w, h int) *Node { n1 := NewNode(STUndef, x, y, w, h, nil, NewID()) return n1 } // IsLeaf returns if this node is a leaf node func (n *Node) IsLeaf() bool { return len(n.children) == 0 } // ID returns this node's id or 0 if it is not viewable func (n *Node) ID() uint64 { if n.IsLeaf() { return n.id } return 0 } // CanResize returns if this node can be resized func (n *Node) CanResize() bool { return n.canResize } // PropScale returns if this node is proportionally scaled func (n *Node) PropScale() bool { return n.propScale } // SetResize sets the resize flag func (n *Node) SetResize(b bool) { n.canResize = b } // SetPropScale sets the propScale flag func (n *Node) SetPropScale(b bool) { n.propScale = b } // Children returns this node's children func (n *Node) Children() []*Node { return n.children } // GetNode returns the node with the given id in the tree of children // that this node has access to or nil if the node with that id cannot be found func (n *Node) GetNode(id uint64) *Node { if n.id == id && n.IsLeaf() { return n } for _, c := range n.children { if c.id == id && c.IsLeaf() { return c } gc := c.GetNode(id) if gc != nil { return gc } } return nil } func (n *Node) vResizeSplit(i int, size int) bool { if i < 0 || i >= len(n.children) { return false } var c1, c2 *Node if i == len(n.children)-1 { c1, c2 = n.children[i-1], n.children[i] } else { c1, c2 = n.children[i], n.children[i+1] } toth := c1.H + c2.H if size >= toth { return false } c2.Y = c1.Y + size c1.Resize(c1.W, size) c2.Resize(c2.W, toth-size) n.markSizes() n.alignSizes(n.W, n.H) return true } func (n *Node) hResizeSplit(i int, size int) bool { if i < 0 || i >= len(n.children) { return false } var c1, c2 *Node if i == len(n.children)-1 { c1, c2 = n.children[i-1], n.children[i] } else { c1, c2 = n.children[i], n.children[i+1] } totw := c1.W + c2.W if size >= totw { return false } c2.X = c1.X + size c1.Resize(size, c1.H) c2.Resize(totw-size, c2.H) n.markSizes() n.alignSizes(n.W, n.H) return true } // ResizeSplit resizes a certain split to a given size func (n *Node) ResizeSplit(size int) bool { // TODO: `size < 0` does not work for some reason if size <= 0 { return false } if len(n.parent.children) <= 1 { // cannot resize a lone node return false } ind := 0 for i, c := range n.parent.children { if c.id == n.id { ind = i } } if n.parent.Kind == STVert { return n.parent.vResizeSplit(ind, size) } return n.parent.hResizeSplit(ind, size) } // Resize sets this node's size and resizes all children accordingly func (n *Node) Resize(w, h int) { n.W, n.H = w, h if n.IsLeaf() { return } x, y := n.X, n.Y totw, toth := 0, 0 for _, c := range n.children { cW := int(float64(w) * c.propW) cH := int(float64(h) * c.propH) c.X, c.Y = x, y c.Resize(cW, cH) if n.Kind == STHoriz { x += cW totw += cW } else { y += cH toth += cH } } n.alignSizes(totw, toth) } func (n *Node) alignSizes(totw, toth int) { // Make sure that there are no off-by-one problems with the rounding // of the sizes by making the final split fill the screen if n.Kind == STVert && toth != n.H { last := n.children[len(n.children)-1] last.Resize(last.W, last.H+n.H-toth) } else if n.Kind == STHoriz && totw != n.W { last := n.children[len(n.children)-1] last.Resize(last.W+n.W-totw, last.H) } } // Resets all proportions for children func (n *Node) markSizes() { for _, c := range n.children { c.propW = float64(c.W) / float64(n.W) c.propH = float64(c.H) / float64(n.H) c.markSizes() } } func (n *Node) markResize() { n.markSizes() n.Resize(n.W, n.H) } // vsplits a vertical split and returns the id of the new split func (n *Node) vVSplit(right bool) uint64 { ind := 0 for i, c := range n.parent.children { if c.id == n.id { ind = i } } return n.parent.hVSplit(ind, right) } // hsplits a horizontal split func (n *Node) hHSplit(bottom bool) uint64 { ind := 0 for i, c := range n.parent.children { if c.id == n.id { ind = i } } return n.parent.vHSplit(ind, bottom) } // Returns the size of the non-resizable area and the number of resizable // splits func (n *Node) getResizeInfo(h bool) (int, int) { numr := 0 numnr := 0 nonr := 0 for _, c := range n.children { if !c.CanResize() { if h { nonr += c.H } else { nonr += c.W } numnr++ } else { numr++ } } // if there are no resizable splits make them all resizable if numr == 0 { numr = numnr } return nonr, numr } func (n *Node) applyNewSize(size int, h bool) { a := n.X if h { a = n.Y } for _, c := range n.children { if h { c.Y = a } else { c.X = a } if c.CanResize() { if h { c.Resize(c.W, size) } else { c.Resize(size, c.H) } } if h { a += c.H } else { a += c.H } } n.markResize() } // hsplits a vertical split func (n *Node) vHSplit(i int, right bool) uint64 { if n.IsLeaf() { newid := NewID() hn1 := NewNode(STHoriz, n.X, n.Y, n.W, n.H/2, n, n.id) hn2 := NewNode(STHoriz, n.X, n.Y+hn1.H, n.W, n.H/2, n, newid) if !right { hn1.id, hn2.id = hn2.id, hn1.id } n.children = append(n.children, hn1, hn2) n.markResize() return newid } else { nonrh, numr := n.getResizeInfo(true) // size of resizable area height := (n.H - nonrh) / (numr + 1) newid := NewID() hn := NewNode(STHoriz, n.X, 0, n.W, height, n, newid) // insert the node into the correct slot n.children = append(n.children, nil) inspos := i if right { inspos++ } copy(n.children[inspos+1:], n.children[inspos:]) n.children[inspos] = hn n.applyNewSize(height, true) return newid } } // vsplits a horizontal split func (n *Node) hVSplit(i int, right bool) uint64 { if n.IsLeaf() { newid := NewID() vn1 := NewNode(STVert, n.X, n.Y, n.W/2, n.H, n, n.id) vn2 := NewNode(STVert, n.X+vn1.W, n.Y, n.W/2, n.H, n, newid) if !right { vn1.id, vn2.id = vn2.id, vn1.id } n.children = append(n.children, vn1, vn2) n.markResize() return newid } else { nonrw, numr := n.getResizeInfo(false) width := (n.W - nonrw) / (numr + 1) newid := NewID() vn := NewNode(STVert, 0, n.Y, width, n.H, n, newid) // Inser the node into the correct slot n.children = append(n.children, nil) inspos := i if right { inspos++ } copy(n.children[inspos+1:], n.children[inspos:]) n.children[inspos] = vn n.applyNewSize(width, false) return newid } } // HSplit creates a horizontal split and returns the id of the new split // bottom specifies if the new split should be created on the top or bottom // of the current split func (n *Node) HSplit(bottom bool) uint64 { if !n.IsLeaf() { return 0 } if n.Kind == STUndef { n.Kind = STVert } if n.Kind == STVert { return n.vHSplit(0, bottom) } return n.hHSplit(bottom) } // VSplit creates a vertical split and returns the id of the new split // right specifies if the new split should be created on the right or left // of the current split func (n *Node) VSplit(right bool) uint64 { if !n.IsLeaf() { return 0 } if n.Kind == STUndef { n.Kind = STHoriz } if n.Kind == STVert { return n.vVSplit(right) } return n.hVSplit(0, right) } // unsplits the child of a split func (n *Node) unsplit(i int) { copy(n.children[i:], n.children[i+1:]) n.children[len(n.children)-1] = nil n.children = n.children[:len(n.children)-1] h := n.Kind == STVert nonrs, numr := n.getResizeInfo(h) if numr == 0 { // This means that this was the last child // The parent will get cleaned up in the next iteration and // will resolve all sizing issues with its parent return } size := (n.W - nonrs) / numr if h { size = (n.H - nonrs) / numr } n.applyNewSize(size, h) } // Unsplit deletes this split and resizes everything // else accordingly func (n *Node) Unsplit() bool { if !n.IsLeaf() || n.parent == nil { return false } ind := 0 for i, c := range n.parent.children { if c.id == n.id { ind = i } } n.parent.unsplit(ind) if n.parent.IsLeaf() { return n.parent.Unsplit() } n.parent.flatten() return true } // flattens the tree by removing unnecessary intermediate parents that have only one child // and handles the side effect of it func (n *Node) flatten() { if n.parent == nil || len(n.children) != 1 { return } ind := 0 for i, c := range n.parent.children { if c.id == n.id { ind = i } } // Replace current node with its child node to remove chained parent successor := n.children[0] n.parent.children[ind] = successor successor.parent = n.parent // Maintain the tree in a consistent state: any child node's kind (horiz vs vert) // should be the opposite of its parent's kind. if successor.IsLeaf() { successor.Kind = n.Kind } else { // If the successor node has children, that means it is a chained parent as well. // Therefore it can be replaced by its own children. origsize := len(n.parent.children) // Let's say we have 5 children and want to replace [2] with its children [a] [b] [c] // [0] [1] [2] [3] [4] --> [0] [1] [a] [b] [c] [3] [4] // insertcount will be `3 - 1 = 2` in this case insertcount := len(successor.children) - 1 n.parent.children = append(n.parent.children, make([]*Node, insertcount)...) copy(n.parent.children[ind+insertcount+1:], n.parent.children[ind+1:origsize]) copy(n.parent.children[ind:], successor.children) for i := 0; i < len(successor.children); i++ { n.parent.children[ind+i].parent = n.parent } } // Update propW and propH since the parent of the children has been updated, // so the children have new siblings n.parent.markSizes() } // String returns the string form of the node and all children (used for debugging) func (n *Node) String() string { var strf func(n *Node, ident int) string strf = func(n *Node, ident int) string { marker := "|" if n.Kind == STHoriz { marker = "-" } str := fmt.Sprint(strings.Repeat("\t", ident), marker, n.View, n.id) if n.IsLeaf() { str += "ðŸ" } str += "\n" for _, c := range n.children { str += strf(c, ident+1) } return str } return strf(n, 0) } zyedidia-micro-6a62575/internal/util/0000775000175000017510000000000015125206537017034 5ustar nileshnileshzyedidia-micro-6a62575/internal/util/util_test.go0000664000175000017510000000131415125206537021376 0ustar nileshnileshpackage util import ( "testing" "github.com/stretchr/testify/assert" ) func TestStringWidth(t *testing.T) { bytes := []byte("\tPot să \tmănânc sticlă È™i ea nu mă răneÈ™te.") n := StringWidth(bytes, 23, 4) assert.Equal(t, 26, n) } func TestSliceVisualEnd(t *testing.T) { s := []byte("\thello") slc, n, _ := SliceVisualEnd(s, 2, 4) assert.Equal(t, []byte("\thello"), slc) assert.Equal(t, 2, n) slc, n, _ = SliceVisualEnd(s, 1, 4) assert.Equal(t, []byte("\thello"), slc) assert.Equal(t, 1, n) slc, n, _ = SliceVisualEnd(s, 4, 4) assert.Equal(t, []byte("hello"), slc) assert.Equal(t, 0, n) slc, n, _ = SliceVisualEnd(s, 5, 4) assert.Equal(t, []byte("ello"), slc) assert.Equal(t, 0, n) } zyedidia-micro-6a62575/internal/util/util.go0000664000175000017510000004411215125206537020342 0ustar nileshnileshpackage util import ( "archive/zip" "bytes" "crypto/md5" "errors" "fmt" "io" "io/fs" "net/http" "net/url" "os" "os/user" "path/filepath" "regexp" "runtime" "strconv" "strings" "time" "unicode" "unicode/utf8" "github.com/blang/semver" runewidth "github.com/mattn/go-runewidth" ) var ( // These variables should be set by the linker when compiling // Version is the version number or commit hash Version = "0.0.0-unknown" // SemVersion is the Semantic version SemVersion semver.Version // CommitHash is the commit this version was built on CommitHash = "Unknown" // CompileDate is the date this binary was compiled on CompileDate = "Unknown" // Debug logging Debug = "OFF" // FakeCursor is used to disable the terminal cursor and have micro // draw its own (enabled for windows consoles where the cursor is slow) FakeCursor = false // Stdout is a buffer that is written to stdout when micro closes Stdout *bytes.Buffer // Sigterm is a channel where micro exits when written Sigterm chan os.Signal // To be used for fails on (over-)write with safe writes ErrOverwrite = OverwriteError{} ) // To be used for file writes before umask is applied const FileMode os.FileMode = 0666 const BackupSuffix = ".micro-backup" const OverwriteFailMsg = `An error occurred while writing to the file: %s The file may be corrupted now. The good news is that it has been successfully backed up. Next time you open this file with Micro, Micro will ask if you want to recover it from the backup. The backup path is: %s` // OverwriteError is a custom error to add additional information type OverwriteError struct { What error BackupName string } func (e OverwriteError) Error() string { return fmt.Sprintf(OverwriteFailMsg, e.What, e.BackupName) } func (e OverwriteError) Is(target error) bool { return target == ErrOverwrite } func (e OverwriteError) Unwrap() error { return e.What } func init() { var err error SemVersion, err = semver.Make(Version) if err != nil { fmt.Println("Invalid version: ", Version, err) } _, wt := os.LookupEnv("WT_SESSION") if runtime.GOOS == "windows" && !wt { FakeCursor = true } Stdout = new(bytes.Buffer) } // SliceEnd returns a byte slice where the index is a rune index // Slices off the start of the slice func SliceEnd(slc []byte, index int) []byte { len := len(slc) i := 0 totalSize := 0 for totalSize < len { if i >= index { return slc[totalSize:] } _, _, size := DecodeCharacter(slc[totalSize:]) totalSize += size i++ } return slc[totalSize:] } // SliceEndStr is the same as SliceEnd but for strings func SliceEndStr(str string, index int) string { len := len(str) i := 0 totalSize := 0 for totalSize < len { if i >= index { return str[totalSize:] } _, _, size := DecodeCharacterInString(str[totalSize:]) totalSize += size i++ } return str[totalSize:] } // SliceStart returns a byte slice where the index is a rune index // Slices off the end of the slice func SliceStart(slc []byte, index int) []byte { len := len(slc) i := 0 totalSize := 0 for totalSize < len { if i >= index { return slc[:totalSize] } _, _, size := DecodeCharacter(slc[totalSize:]) totalSize += size i++ } return slc[:totalSize] } // SliceStartStr is the same as SliceStart but for strings func SliceStartStr(str string, index int) string { len := len(str) i := 0 totalSize := 0 for totalSize < len { if i >= index { return str[:totalSize] } _, _, size := DecodeCharacterInString(str[totalSize:]) totalSize += size i++ } return str[:totalSize] } // SliceVisualEnd will take a byte slice and slice off the start // up to a given visual index. If the index is in the middle of a // rune the number of visual columns into the rune will be returned // It will also return the char pos of the first character of the slice func SliceVisualEnd(b []byte, n, tabsize int) ([]byte, int, int) { width := 0 i := 0 for len(b) > 0 { r, _, size := DecodeCharacter(b) w := 0 switch r { case '\t': ts := tabsize - (width % tabsize) w = ts default: w = runewidth.RuneWidth(r) } if width+w > n { return b, n - width, i } width += w b = b[size:] i++ } return b, n - width, i } // Abs is a simple absolute value function for ints func Abs(n int) int { if n < 0 { return -n } return n } // StringWidth returns the visual width of a byte array indexed from 0 to n (rune index) // with a given tabsize func StringWidth(b []byte, n, tabsize int) int { if n <= 0 { return 0 } i := 0 width := 0 for len(b) > 0 { r, _, size := DecodeCharacter(b) b = b[size:] switch r { case '\t': ts := tabsize - (width % tabsize) width += ts default: width += runewidth.RuneWidth(r) } i++ if i == n { return width } } return width } // Min takes the min of two ints func Min(a, b int) int { if a > b { return b } return a } // Max takes the max of two ints func Max(a, b int) int { if a > b { return a } return b } // FSize gets the size of a file func FSize(f *os.File) int64 { fi, _ := f.Stat() return fi.Size() } // IsWordChar returns whether or not a rune is a 'word character' // Word characters are defined as numbers, letters or sub-word delimiters func IsWordChar(r rune) bool { return IsAlphanumeric(r) || IsSubwordDelimiter(r) } // IsNonWordChar returns whether or not a rune is not a 'word character' // Non word characters are defined as all characters not being numbers, letters or sub-word delimiters // See IsWordChar() func IsNonWordChar(r rune) bool { return !IsWordChar(r) } // IsSubwordDelimiter returns whether or not a rune is a 'sub-word delimiter character' // i.e. is considered a part of the word and is used as a delimiter between sub-words of the word. // For now the only sub-word delimiter character is '_'. func IsSubwordDelimiter(r rune) bool { return r == '_' } // IsAlphanumeric returns whether or not a rune is an 'alphanumeric character' // Alphanumeric characters are defined as numbers or letters func IsAlphanumeric(r rune) bool { return unicode.IsLetter(r) || unicode.IsNumber(r) } // IsUpperAlphanumeric returns whether or not a rune is an 'upper alphanumeric character' // Upper alphanumeric characters are defined as numbers or upper-case letters func IsUpperAlphanumeric(r rune) bool { return IsUpperLetter(r) || unicode.IsNumber(r) } // IsLowerAlphanumeric returns whether or not a rune is a 'lower alphanumeric character' // Lower alphanumeric characters are defined as numbers or lower-case letters func IsLowerAlphanumeric(r rune) bool { return IsLowerLetter(r) || unicode.IsNumber(r) } // IsUpperLetter returns whether or not a rune is an 'upper letter character' // Upper letter characters are defined as upper-case letters func IsUpperLetter(r rune) bool { // unicode.IsUpper() returns true for letters only return unicode.IsUpper(r) } // IsLowerLetter returns whether or not a rune is a 'lower letter character' // Lower letter characters are defined as lower-case letters func IsLowerLetter(r rune) bool { // unicode.IsLower() returns true for letters only return unicode.IsLower(r) } // Spaces returns a string with n spaces func Spaces(n int) string { return strings.Repeat(" ", n) } // IsSpaces checks if a given string is only spaces func IsSpaces(str []byte) bool { for _, c := range str { if c != ' ' { return false } } return true } // IsSpacesOrTabs checks if a given string contains only spaces and tabs func IsSpacesOrTabs(str []byte) bool { for _, c := range str { if c != ' ' && c != '\t' { return false } } return true } // IsWhitespace returns true if the given rune is a space, tab, or newline func IsWhitespace(c rune) bool { return unicode.IsSpace(c) } // IsBytesWhitespace returns true if the given bytes are all whitespace func IsBytesWhitespace(b []byte) bool { for _, c := range b { if !IsWhitespace(rune(c)) { return false } } return true } // RunePos returns the rune index of a given byte index // Make sure the byte index is not between code points func RunePos(b []byte, i int) int { return CharacterCount(b[:i]) } // IndexAnyUnquoted returns the first position in s of a character from chars. // Escaped (with backslash) and quoted (with single or double quotes) characters // are ignored. Returns -1 if not successful func IndexAnyUnquoted(s, chars string) int { var e bool var q rune for i, r := range s { if e { e = false } else if (q == 0 || q == '"') && r == '\\' { e = true } else if r == q { q = 0 } else if q == 0 && (r == '\'' || r == '"') { q = r } else if q == 0 && strings.IndexRune(chars, r) >= 0 { return i } } return -1 } // MakeRelative will attempt to make a relative path between path and base func MakeRelative(path, base string) (string, error) { if len(path) > 0 { rel, err := filepath.Rel(base, path) if err != nil { return path, err } return rel, nil } return path, nil } // ReplaceHome takes a path as input and replaces ~ at the start of the path with the user's // home directory. Does nothing if the path does not start with '~'. func ReplaceHome(path string) (string, error) { if !strings.HasPrefix(path, "~") { return path, nil } var userData *user.User var err error homeString := strings.Split(path, "/")[0] if homeString == "~" { userData, err = user.Current() if err != nil { return "", errors.New("Could not find user: " + err.Error()) } } else { userData, err = user.Lookup(homeString[1:]) if err != nil { return "", errors.New("Could not find user: " + err.Error()) } } home := userData.HomeDir return strings.Replace(path, homeString, home, 1), nil } // GetPathAndCursorPosition returns a filename without everything following a `:` // This is used for opening files like util.go:10:5 to specify a line and column // Special cases like Windows Absolute path (C:\myfile.txt:10:5) are handled correctly. func GetPathAndCursorPosition(path string) (string, []string) { re := regexp.MustCompile(`([\s\S]+?)(?::(\d+))(?::(\d+))?$`) match := re.FindStringSubmatch(path) // no lines/columns were specified in the path, return just the path with no cursor location if len(match) == 0 { return path, nil } else if match[len(match)-1] != "" { // if the last capture group match isn't empty then both line and column were provided return match[1], match[2:] } // if it was empty, then only a line was provided, so default to column 0 return match[1], []string{match[2], "0"} } // GetModTime returns the last modification time for a given file func GetModTime(path string) (time.Time, error) { info, err := os.Stat(path) if err != nil { return time.Now(), err } return info.ModTime(), nil } func HashStringMd5(str string) string { return fmt.Sprintf("%x", md5.Sum([]byte(str))) } // EscapePathUrl encodes the path in URL query form func EscapePathUrl(path string) string { return url.QueryEscape(filepath.ToSlash(path)) } // EscapePathLegacy replaces every path separator in a given path with a % func EscapePathLegacy(path string) string { path = filepath.ToSlash(path) if runtime.GOOS == "windows" { // ':' is not valid in a path name on Windows but is ok on Unix path = strings.ReplaceAll(path, ":", "%") } return strings.ReplaceAll(path, "/", "%") } // DetermineEscapePath escapes a path, determining whether it should be escaped // using URL encoding (preferred, since it encodes unambiguously) or // legacy encoding with '%' (for backward compatibility, if the legacy-escaped // path exists in the given directory). // In case the length of the escaped path (plus the backup extension) exceeds // the filename length limit, a hash of the path is returned instead. In such // case the second return value is the name of a file the original path should // be saved to (since the original path cannot be derived from its hash). // Otherwise the second return value is an empty string. func DetermineEscapePath(dir string, path string) (string, string) { url := filepath.Join(dir, EscapePathUrl(path)) if _, err := os.Stat(url); err == nil { return url, "" } legacy := filepath.Join(dir, EscapePathLegacy(path)) if _, err := os.Stat(legacy); err == nil { return legacy, "" } if len(url)+len(BackupSuffix) > 255 { hash := HashStringMd5(path) return filepath.Join(dir, hash), filepath.Join(dir, hash+".path") } return url, "" } // GetLeadingWhitespace returns the leading whitespace of the given byte array func GetLeadingWhitespace(b []byte) []byte { ws := []byte{} for len(b) > 0 { r, _, size := DecodeCharacter(b) if r == ' ' || r == '\t' { ws = append(ws, byte(r)) } else { break } b = b[size:] } return ws } // GetTrailingWhitespace returns the trailing whitespace of the given byte array func GetTrailingWhitespace(b []byte) []byte { ws := []byte{} for len(b) > 0 { r, size := utf8.DecodeLastRune(b) if IsWhitespace(r) { ws = append([]byte(string(r)), ws...) } else { break } b = b[:len(b)-size] } return ws } // HasTrailingWhitespace returns true if the given byte array ends with a whitespace func HasTrailingWhitespace(b []byte) bool { r, _ := utf8.DecodeLastRune(b) return IsWhitespace(r) } // IntOpt turns a float64 setting to an int func IntOpt(opt any) int { return int(opt.(float64)) } // GetCharPosInLine gets the char position of a visual x y // coordinate (this is necessary because tabs are 1 char but // 4 visual spaces) func GetCharPosInLine(b []byte, visualPos int, tabsize int) int { // Scan rune by rune until we exceed the visual width that we are // looking for. Then we can return the character position we have found i := 0 // char pos width := 0 // string visual width for len(b) > 0 { r, _, size := DecodeCharacter(b) b = b[size:] switch r { case '\t': ts := tabsize - (width % tabsize) width += ts default: width += runewidth.RuneWidth(r) } if width >= visualPos { if width == visualPos { i++ } break } i++ } return i } // ParseBool is almost exactly like strconv.ParseBool, except it also accepts 'on' and 'off' // as 'true' and 'false' respectively func ParseBool(str string) (bool, error) { if str == "on" { return true, nil } if str == "off" { return false, nil } return strconv.ParseBool(str) } // Clamp clamps a value between min and max func Clamp(val, min, max int) int { if val < min { val = min } else if val > max { val = max } return val } // IsAutocomplete returns whether a character should begin an autocompletion. func IsAutocomplete(c rune) bool { return c == '.' || IsWordChar(c) } // String converts a byte array to a string (for lua plugins) func String(s []byte) string { return string(s) } // Unzip unzips a file to given folder func Unzip(src, dest string) error { r, err := zip.OpenReader(src) if err != nil { return err } defer r.Close() os.MkdirAll(dest, 0755) // Closure to address file descriptors issue with all the deferred .Close() methods extractAndWriteFile := func(f *zip.File) error { rc, err := f.Open() if err != nil { return err } defer rc.Close() path := filepath.Join(dest, f.Name) // Check for ZipSlip (Directory traversal) if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) { return fmt.Errorf("illegal file path: %s", path) } if f.FileInfo().IsDir() { os.MkdirAll(path, f.Mode()) } else { os.MkdirAll(filepath.Dir(path), f.Mode()) f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) if err != nil { return err } defer f.Close() _, err = io.Copy(f, rc) if err != nil { return err } } return nil } for _, f := range r.File { err := extractAndWriteFile(f) if err != nil { return err } } return nil } // HttpRequest returns a new http.Client for making custom requests (for lua plugins) func HttpRequest(method string, url string, headers []string) (resp *http.Response, err error) { client := http.Client{} req, err := http.NewRequest(method, url, nil) if err != nil { return nil, err } for i := 0; i < len(headers); i += 2 { req.Header.Add(headers[i], headers[i+1]) } return client.Do(req) } // SafeWrite writes bytes to a file in a "safe" way, preventing loss of the // contents of the file if it fails to write the new contents. // This means that the file is not overwritten directly but by writing to a // temporary file first. // // If rename is true, write is performed atomically, by renaming the temporary // file to the target file after the data is successfully written to the // temporary file. This guarantees that the file will not remain in a corrupted // state, but it also has limitations, e.g. the file should not be a symlink // (otherwise SafeWrite silently replaces this symlink with a regular file), // the file creation date in Linux is not preserved (since the file inode // changes) etc. Use SafeWrite with rename=true for files that are only created // and used by micro for its own needs and are not supposed to be used directly // by the user. // // If rename is false, write is performed by overwriting the target file after // the data is successfully written to the temporary file. // This means that the target file may remain corrupted if overwrite fails, // but in such case the temporary file is preserved as a backup so the file // can be recovered later. So it is less convenient than atomic write but more // universal. Use SafeWrite with rename=false for files that may be managed // directly by the user, like settings.json and bindings.json. func SafeWrite(path string, bytes []byte, rename bool) error { var err error if _, err = os.Stat(path); err != nil { if !errors.Is(err, fs.ErrNotExist) { return err } // Force rename for new files! rename = true } var file *os.File if !rename { file, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE, FileMode) if err != nil { return err } defer file.Close() } tmp := path + BackupSuffix err = os.WriteFile(tmp, bytes, FileMode) if err != nil { os.Remove(tmp) return err } if rename { err = os.Rename(tmp, path) } else { err = file.Truncate(0) if err == nil { _, err = file.Write(bytes) } if err == nil { err = file.Sync() } } if err != nil { if rename { os.Remove(tmp) } else { err = OverwriteError{err, tmp} } return err } if !rename { os.Remove(tmp) } return nil } zyedidia-micro-6a62575/internal/util/unicode.go0000664000175000017510000000442415125206537021015 0ustar nileshnileshpackage util import ( "unicode" "unicode/utf8" ) // Unicode is annoying. A "code point" (rune in Go-speak) may need up to // 4 bytes to represent it. In general, a code point will represent a // complete character, but this is not always the case. A character with // accents may be made up of multiple code points (the code point for the // original character, and additional code points for each accent/marking). // The functions below are meant to help deal with these additional "combining" // code points. In underlying operations (search, replace, etc...), micro will // treat a character with combining code points as just the original code point. // For rendering, micro will display the combining characters. It's not perfect // but it's pretty good. var minMark = rune(unicode.Mark.R16[0].Lo) func isMark(r rune) bool { // Fast path if r < minMark { return false } return unicode.In(r, unicode.Mark) } // DecodeCharacter returns the next character from an array of bytes // A character is a rune along with any accompanying combining runes func DecodeCharacter(b []byte) (rune, []rune, int) { r, size := utf8.DecodeRune(b) b = b[size:] c, s := utf8.DecodeRune(b) var combc []rune for isMark(c) { combc = append(combc, c) size += s b = b[s:] c, s = utf8.DecodeRune(b) } return r, combc, size } // DecodeCharacterInString returns the next character from a string // A character is a rune along with any accompanying combining runes func DecodeCharacterInString(str string) (rune, []rune, int) { r, size := utf8.DecodeRuneInString(str) str = str[size:] c, s := utf8.DecodeRuneInString(str) var combc []rune for isMark(c) { combc = append(combc, c) size += s str = str[s:] c, s = utf8.DecodeRuneInString(str) } return r, combc, size } // CharacterCount returns the number of characters in a byte array // Similar to utf8.RuneCount but for unicode characters func CharacterCount(b []byte) int { s := 0 for len(b) > 0 { r, size := utf8.DecodeRune(b) if !isMark(r) { s++ } b = b[size:] } return s } // CharacterCount returns the number of characters in a string // Similar to utf8.RuneCountInString but for unicode characters func CharacterCountInString(str string) int { s := 0 for _, r := range str { if !isMark(r) { s++ } } return s } zyedidia-micro-6a62575/internal/util/profile.go0000664000175000017510000000120115125206537021015 0ustar nileshnileshpackage util import ( "fmt" "log" "runtime" "time" humanize "github.com/dustin/go-humanize" ) // GetMemStats returns a string describing the memory usage and gc time used so far func GetMemStats() string { var memstats runtime.MemStats runtime.ReadMemStats(&memstats) return fmt.Sprintf("Alloc: %s, Sys: %s, GC: %d, PauseTotalNs: %dns", humanize.Bytes(memstats.Alloc), humanize.Bytes(memstats.Sys), memstats.NumGC, memstats.PauseTotalNs) } func Tic(s string) time.Time { log.Println("START:", s) return time.Now() } func Toc(start time.Time) { end := time.Now() log.Println("END: ElapsedTime in seconds:", end.Sub(start)) } zyedidia-micro-6a62575/internal/util/lua.go0000664000175000017510000000151315125206537020144 0ustar nileshnileshpackage util // LuaRuneAt is a helper function for lua plugins to return the rune // at an index within a string func LuaRuneAt(str string, runeidx int) string { i := 0 for len(str) > 0 { r, _, size := DecodeCharacterInString(str) str = str[size:] if i == runeidx { return string(r) } i++ } return "" } // LuaGetLeadingWhitespace returns the leading whitespace of a string (used by lua plugins) func LuaGetLeadingWhitespace(s string) string { ws := []byte{} for len(s) > 0 { r, _, size := DecodeCharacterInString(s) if r == ' ' || r == '\t' { ws = append(ws, byte(r)) } else { break } s = s[size:] } return string(ws) } // LuaIsWordChar returns true if the first rune in a string is a word character func LuaIsWordChar(s string) bool { r, _, _ := DecodeCharacterInString(s) return IsWordChar(r) } zyedidia-micro-6a62575/internal/shell/0000775000175000017510000000000015125206537017166 5ustar nileshnileshzyedidia-micro-6a62575/internal/shell/terminal.go0000664000175000017510000000574115125206537021337 0ustar nileshnileshpackage shell import ( "bytes" "os/exec" "strconv" "github.com/micro-editor/terminal" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/screen" ) type TermType int type CallbackFunc func(string) const ( TTClose = iota // Should be closed TTRunning // Currently running a command TTDone // Finished running a command ) var CloseTerms chan bool func init() { CloseTerms = make(chan bool) } // A Terminal holds information for the terminal emulator type Terminal struct { State terminal.State Term *terminal.VT title string Status TermType Selection [2]buffer.Loc wait bool getOutput bool output *bytes.Buffer callback CallbackFunc } // HasSelection returns whether this terminal has a valid selection func (t *Terminal) HasSelection() bool { return t.Selection[0] != t.Selection[1] } func (t *Terminal) Name() string { return t.title } // GetSelection returns the selected text func (t *Terminal) GetSelection(width int) string { start := t.Selection[0] end := t.Selection[1] if start.GreaterThan(end) { start, end = end, start } var ret string var l buffer.Loc for y := start.Y; y <= end.Y; y++ { for x := 0; x < width; x++ { l.X, l.Y = x, y if l.GreaterEqual(start) && l.LessThan(end) { c, _, _ := t.State.Cell(x, y) ret += string(c) } } } return ret } // Start begins a new command in this terminal with a given view func (t *Terminal) Start(execCmd []string, getOutput bool, wait bool, callback func(out string, userargs []any), userargs []any) error { if len(execCmd) <= 0 { return nil } cmd := exec.Command(execCmd[0], execCmd[1:]...) t.output = nil if getOutput { t.output = bytes.NewBuffer([]byte{}) cmd.Stdout = t.output } Term, _, err := terminal.Start(&t.State, cmd) if err != nil { return err } t.Term = Term t.getOutput = getOutput t.Status = TTRunning t.title = execCmd[0] + ":" + strconv.Itoa(cmd.Process.Pid) t.wait = wait t.callback = func(out string) { callback(out, userargs) } go func() { for { err := Term.Parse() if err != nil { Term.Write([]byte("Press enter to close")) screen.Redraw() break } screen.Redraw() } t.Stop() }() return nil } // Stop stops execution of the terminal and sets the Status // to TTDone func (t *Terminal) Stop() { t.Term.File().Close() t.Term.Close() if t.wait { t.Status = TTDone } else { t.Close() CloseTerms <- true } } // Close sets the Status to TTClose indicating that the terminal // is done and should be closed func (t *Terminal) Close() { t.Status = TTClose // call the lua function that the user has given as a callback if t.getOutput { if t.callback != nil { Jobs <- JobFunction{ Function: func(out string, args []any) { t.callback(out) }, Output: t.output.String(), Args: nil, } } } } // WriteString writes a given string to this terminal's pty func (t *Terminal) WriteString(str string) { t.Term.File().WriteString(str) } zyedidia-micro-6a62575/internal/shell/shell.go0000664000175000017510000000635115125206537020631 0ustar nileshnileshpackage shell import ( "bytes" "errors" "fmt" "io" "os" "os/exec" "os/signal" shellquote "github.com/kballard/go-shellquote" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) // ExecCommand executes a command using exec // It returns any output/errors func ExecCommand(name string, arg ...string) (string, error) { var err error cmd := exec.Command(name, arg...) outputBytes := &bytes.Buffer{} cmd.Stdout = outputBytes cmd.Stderr = outputBytes err = cmd.Start() if err != nil { return "", err } err = cmd.Wait() // wait for command to finish outstring := outputBytes.String() return outstring, err } // RunCommand executes a shell command and returns the output/error func RunCommand(input string) (string, error) { args, err := shellquote.Split(input) if err != nil { return "", err } if len(args) == 0 { return "", errors.New("No arguments") } inputCmd := args[0] return ExecCommand(inputCmd, args[1:]...) } // RunBackgroundShell runs a shell command in the background // It returns a function which will run the command and returns a string // message result func RunBackgroundShell(input string) (func() string, error) { args, err := shellquote.Split(input) if err != nil { return nil, err } if len(args) == 0 { return nil, errors.New("No arguments") } inputCmd := args[0] return func() string { output, err := RunCommand(input) str := output if err != nil { str = fmt.Sprint(inputCmd, " exited with error: ", err, ": ", output) } return str }, nil } // RunInteractiveShell runs a shellcommand interactively func RunInteractiveShell(input string, wait bool, getOutput bool) (string, error) { args, err := shellquote.Split(input) if err != nil { return "", err } if len(args) == 0 { return "", errors.New("No arguments") } inputCmd := args[0] // Shut down the screen because we're going to interact directly with the shell screenb := screen.TempFini() args = args[1:] // Set up everything for the command outputBytes := &bytes.Buffer{} cmd := exec.Command(inputCmd, args...) cmd.Stdin = os.Stdin if getOutput { cmd.Stdout = io.MultiWriter(os.Stdout, outputBytes) } else { cmd.Stdout = os.Stdout } cmd.Stderr = os.Stderr // This is a trap for Ctrl-C so that it doesn't kill micro // micro is killed if the signal is ignored only on Windows, so it is // received c := make(chan os.Signal, 1) signal.Reset(os.Interrupt) signal.Notify(c, os.Interrupt) err = cmd.Start() if err == nil { err = cmd.Wait() if wait { // This is just so we don't return right away and let the user press enter to return screen.TermMessage("") } } else { screen.TermMessage(err) } output := outputBytes.String() // Start the screen back up screen.TempStart(screenb) signal.Notify(util.Sigterm, os.Interrupt) signal.Stop(c) return output, err } // UserCommand runs the shell command // The openTerm argument specifies whether a terminal should be opened (for viewing output // or interacting with stdin) // func UserCommand(input string, openTerm bool, waitToFinish bool) string { // if !openTerm { // RunBackgroundShell(input) // return "" // } else { // output, _ := RunInteractiveShell(input, waitToFinish, false) // return output // } // } zyedidia-micro-6a62575/internal/shell/job.go0000664000175000017510000000531515125206537020273 0ustar nileshnileshpackage shell import ( "bytes" "io" "os/exec" ) var Jobs chan JobFunction func init() { Jobs = make(chan JobFunction, 100) } // Jobs are the way plugins can run processes in the background // A job is simply a process that gets executed asynchronously // There are callbacks for when the job exits, when the job creates stdout // and when the job creates stderr // These jobs run in a separate goroutine but the lua callbacks need to be // executed in the main thread (where the Lua VM is running) so they are // put into the jobs channel which gets read by the main loop // JobFunction is a representation of a job (this data structure is what is loaded // into the jobs channel) type JobFunction struct { Function func(string, []any) Output string Args []any } // A CallbackFile is the data structure that makes it possible to catch stderr and stdout write events type CallbackFile struct { io.Writer callback func(string, []any) args []any } // Job stores the executing command for the job, and the stdin pipe type Job struct { *exec.Cmd Stdin io.WriteCloser } func (f *CallbackFile) Write(data []byte) (int, error) { // This is either stderr or stdout // In either case we create a new job function callback and put it in the jobs channel jobFunc := JobFunction{f.callback, string(data), f.args} Jobs <- jobFunc return f.Writer.Write(data) } // JobStart starts a shell command in the background with the given callbacks // It returns an *exec.Cmd as the job id func JobStart(cmd string, onStdout, onStderr, onExit func(string, []any), userargs ...any) *Job { return JobSpawn("sh", []string{"-c", cmd}, onStdout, onStderr, onExit, userargs...) } // JobSpawn starts a process with args in the background with the given callbacks // It returns an *exec.Cmd as the job id func JobSpawn(cmdName string, cmdArgs []string, onStdout, onStderr, onExit func(string, []any), userargs ...any) *Job { // Set up everything correctly if the functions have been provided proc := exec.Command(cmdName, cmdArgs...) var outbuf bytes.Buffer if onStdout != nil { proc.Stdout = &CallbackFile{&outbuf, onStdout, userargs} } else { proc.Stdout = &outbuf } if onStderr != nil { proc.Stderr = &CallbackFile{&outbuf, onStderr, userargs} } else { proc.Stderr = &outbuf } stdin, _ := proc.StdinPipe() go func() { // Run the process in the background and create the onExit callback proc.Run() if onExit != nil { jobFunc := JobFunction{onExit, outbuf.String(), userargs} Jobs <- jobFunc } }() return &Job{proc, stdin} } // JobStop kills a job func JobStop(j *Job) { j.Process.Kill() } // JobSend sends the given data into the job's stdin stream func JobSend(j *Job, data string) { j.Stdin.Write([]byte(data)) } zyedidia-micro-6a62575/internal/screen/0000775000175000017510000000000015125206537017336 5ustar nileshnileshzyedidia-micro-6a62575/internal/screen/screen.go0000664000175000017510000001443115125206537021147 0ustar nileshnileshpackage screen import ( "errors" "log" "os" "sync" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/util" ) // Screen is the tcell screen we use to draw to the terminal // Synchronization is used because we poll the screen on a separate // thread and sometimes the screen is shut down by the main thread // (for example on TermMessage) so we don't want to poll a nil/shutdown // screen. TODO: maybe we should worry about polling and drawing at the // same time too. var Screen tcell.Screen // Events is the channel of tcell events var Events chan (tcell.Event) // RestartCallback is called when the screen is restarted after it was // temporarily shut down var RestartCallback func() // The lock is necessary since the screen is polled on a separate thread var lock sync.Mutex // drawChan is a channel that will cause the screen to redraw when // written to even if no event user event has occurred var drawChan chan bool // rawSeq is the list of raw escape sequences that are bound to some actions // via keybindings and thus should be parsed by tcell. We need to register // them in tcell every time we reinitialize the screen, so we need to remember // them in a list var rawSeq = make([]string, 0) // Lock locks the screen lock func Lock() { lock.Lock() } // Unlock unlocks the screen lock func Unlock() { lock.Unlock() } // Redraw schedules a redraw with the draw channel func Redraw() { select { case drawChan <- true: default: // channel is full } } // DrawChan returns the draw channel func DrawChan() chan bool { return drawChan } type screenCell struct { x, y int r rune combc []rune style tcell.Style } var lastCursor screenCell // ShowFakeCursor displays a cursor at the given position by modifying the // style of the given column instead of actually using the terminal cursor // This can be useful in certain terminals such as the windows console where // modifying the cursor location is slow and frequent modifications cause flashing // This keeps track of the most recent fake cursor location and resets it when // a new fake cursor location is specified func ShowFakeCursor(x, y int) { r, combc, style, _ := Screen.GetContent(x, y) Screen.SetContent(lastCursor.x, lastCursor.y, lastCursor.r, lastCursor.combc, lastCursor.style) Screen.SetContent(x, y, r, combc, config.DefStyle.Reverse(true)) lastCursor.x, lastCursor.y = x, y lastCursor.r = r lastCursor.combc = combc lastCursor.style = style } func UseFake() bool { return util.FakeCursor || config.GetGlobalOption("fakecursor").(bool) } // ShowFakeCursorMulti is the same as ShowFakeCursor except it does not // reset previous locations of the cursor // Fake cursors are also necessary to display multiple cursors func ShowFakeCursorMulti(x, y int) { r, _, _, _ := Screen.GetContent(x, y) Screen.SetContent(x, y, r, nil, config.DefStyle.Reverse(true)) } // ShowCursor puts the cursor at the given location using a fake cursor // if enabled or using the terminal cursor otherwise // By default only the windows console will use a fake cursor func ShowCursor(x, y int) { if UseFake() { ShowFakeCursor(x, y) } else { Screen.ShowCursor(x, y) } } // SetContent sets a cell at a point on the screen and makes sure that it is // synced with the last cursor location func SetContent(x, y int, mainc rune, combc []rune, style tcell.Style) { if !Screen.CanDisplay(mainc, true) { mainc = '�' } Screen.SetContent(x, y, mainc, combc, style) if UseFake() && lastCursor.x == x && lastCursor.y == y { lastCursor.r = mainc lastCursor.style = style lastCursor.combc = combc } } // RegisterRawSeq registers a raw escape sequence that should be parsed by tcell func RegisterRawSeq(r string) { for _, seq := range rawSeq { if seq == r { return } } rawSeq = append(rawSeq, r) if Screen != nil { Screen.RegisterRawSeq(r) } } // UnregisterRawSeq unregisters a raw escape sequence that should be parsed by tcell func UnregisterRawSeq(r string) { for i, seq := range rawSeq { if seq == r { rawSeq[i] = rawSeq[len(rawSeq)-1] rawSeq = rawSeq[:len(rawSeq)-1] } } if Screen != nil { Screen.UnregisterRawSeq(r) } } // TempFini shuts the screen down temporarily func TempFini() bool { screenWasNil := Screen == nil if !screenWasNil { Screen.Fini() Lock() Screen = nil } return screenWasNil } // TempStart restarts the screen after it was temporarily disabled func TempStart(screenWasNil bool) { if !screenWasNil { Init() Unlock() if RestartCallback != nil { RestartCallback() } } } // Init creates and initializes the tcell screen func Init() error { drawChan = make(chan bool, 8) // Should we enable true color? truecolor := config.GetGlobalOption("truecolor").(string) if truecolor == "on" || (truecolor == "auto" && os.Getenv("MICRO_TRUECOLOR") == "1") { os.Setenv("TCELL_TRUECOLOR", "enable") } else if truecolor == "off" { os.Setenv("TCELL_TRUECOLOR", "disable") } else { // For "auto", tcell already autodetects truecolor by default } var oldTerm string modifiedTerm := false setXterm := func() { oldTerm = os.Getenv("TERM") os.Setenv("TERM", "xterm-256color") modifiedTerm = true } if config.GetGlobalOption("xterm").(bool) { setXterm() } // Initilize tcell var err error Screen, err = tcell.NewScreen() if err != nil { log.Println("Warning: during screen initialization:", err) log.Println("Falling back to TERM=xterm-256color") setXterm() Screen, err = tcell.NewScreen() if err != nil { return err } } if err = Screen.Init(); err != nil { return err } Screen.SetPaste(config.GetGlobalOption("paste").(bool)) // restore TERM if modifiedTerm { os.Setenv("TERM", oldTerm) } if config.GetGlobalOption("mouse").(bool) { Screen.EnableMouse() } for _, r := range rawSeq { Screen.RegisterRawSeq(r) } return nil } // InitSimScreen initializes a simulation screen for testing purposes func InitSimScreen() (tcell.SimulationScreen, error) { drawChan = make(chan bool, 8) // Initilize tcell var err error s := tcell.NewSimulationScreen("") if s == nil { return nil, errors.New("Failed to get a simulation screen") } if err = s.Init(); err != nil { return nil, err } s.SetSize(80, 24) Screen = s if config.GetGlobalOption("mouse").(bool) { Screen.EnableMouse() } return s, nil } zyedidia-micro-6a62575/internal/screen/message.go0000664000175000017510000000320315125206537021307 0ustar nileshnileshpackage screen import ( "bufio" "fmt" "os" "strconv" "strings" ) // TermMessage sends a message to the user in the terminal. This usually occurs before // micro has been fully initialized -- ie if there is an error in the syntax highlighting // regular expressions // The function must be called when the Screen is not initialized // This will write the message, and wait for the user // to press and key to continue func TermMessage(msg ...any) { screenb := TempFini() fmt.Println(msg...) fmt.Print("\nPress enter to continue") reader := bufio.NewReader(os.Stdin) reader.ReadString('\n') TempStart(screenb) } // TermPrompt prints a prompt and requests the user for a response // The result is matched against a list of options and the index of // the match is returned // If wait is true, the prompt re-prompts until a valid option is // chosen, otherwise if wait is false, -1 is returned for no match func TermPrompt(prompt string, options []string, wait bool) int { screenb := TempFini() idx := -1 // same behavior as do { ... } while (wait && idx == -1) for ok := true; ok; ok = wait && idx == -1 { reader := bufio.NewReader(os.Stdin) fmt.Print(prompt) resp, _ := reader.ReadString('\n') resp = strings.TrimSpace(resp) for i, opt := range options { if resp == opt { idx = i } } if wait && idx == -1 { fmt.Println("\nInvalid choice.") } } TempStart(screenb) return idx } // TermError sends an error to the user in the terminal. Like TermMessage except formatted // as an error func TermError(filename string, lineNum int, err string) { TermMessage(filename + ", " + strconv.Itoa(lineNum) + ": " + err) } zyedidia-micro-6a62575/internal/lua/0000775000175000017510000000000015125206537016640 5ustar nileshnileshzyedidia-micro-6a62575/internal/lua/lua.go0000664000175000017510000006102315125206537017752 0ustar nileshnileshpackage lua import ( "archive/zip" "bytes" "errors" "fmt" "io" "io/ioutil" "math" "math/rand" "net" "net/http" "os" "path" "path/filepath" "regexp" "runtime" "strings" "time" "unicode/utf8" humanize "github.com/dustin/go-humanize" lua "github.com/yuin/gopher-lua" luar "layeh.com/gopher-luar" ) var L *lua.LState // LoadFile loads a lua file func LoadFile(module string, file string, data []byte) error { pluginDef := []byte("module(\"" + module + "\", package.seeall)") if fn, err := L.Load(bytes.NewReader(append(pluginDef, data...)), file); err != nil { return err } else { L.Push(fn) return L.PCall(0, lua.MultRet, nil) } } // Import allows a lua plugin to import a package func Import(pkg string) *lua.LTable { switch pkg { case "fmt": return importFmt() case "io": return importIo() case "io/ioutil", "ioutil": return importIoUtil() case "net": return importNet() case "math": return importMath() case "math/rand": return importMathRand() case "os": return importOs() case "runtime": return importRuntime() case "path": return importPath() case "path/filepath", "filepath": return importFilePath() case "strings": return importStrings() case "regexp": return importRegexp() case "errors": return importErrors() case "time": return importTime() case "unicode/utf8", "utf8": return importUtf8() case "humanize": return importHumanize() case "net/http", "http": return importHTTP() case "archive/zip": return importArchiveZip() default: return nil } } func importFmt() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Errorf", luar.New(L, fmt.Errorf)) L.SetField(pkg, "Fprint", luar.New(L, fmt.Fprint)) L.SetField(pkg, "Fprintf", luar.New(L, fmt.Fprintf)) L.SetField(pkg, "Fprintln", luar.New(L, fmt.Fprintln)) L.SetField(pkg, "Fscan", luar.New(L, fmt.Fscan)) L.SetField(pkg, "Fscanf", luar.New(L, fmt.Fscanf)) L.SetField(pkg, "Fscanln", luar.New(L, fmt.Fscanln)) L.SetField(pkg, "Print", luar.New(L, fmt.Print)) L.SetField(pkg, "Printf", luar.New(L, fmt.Printf)) L.SetField(pkg, "Println", luar.New(L, fmt.Println)) L.SetField(pkg, "Scan", luar.New(L, fmt.Scan)) L.SetField(pkg, "Scanf", luar.New(L, fmt.Scanf)) L.SetField(pkg, "Scanln", luar.New(L, fmt.Scanln)) L.SetField(pkg, "Sprint", luar.New(L, fmt.Sprint)) L.SetField(pkg, "Sprintf", luar.New(L, fmt.Sprintf)) L.SetField(pkg, "Sprintln", luar.New(L, fmt.Sprintln)) L.SetField(pkg, "Sscan", luar.New(L, fmt.Sscan)) L.SetField(pkg, "Sscanf", luar.New(L, fmt.Sscanf)) L.SetField(pkg, "Sscanln", luar.New(L, fmt.Sscanln)) return pkg } func importIo() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Copy", luar.New(L, io.Copy)) L.SetField(pkg, "CopyN", luar.New(L, io.CopyN)) L.SetField(pkg, "EOF", luar.New(L, io.EOF)) L.SetField(pkg, "ErrClosedPipe", luar.New(L, io.ErrClosedPipe)) L.SetField(pkg, "ErrNoProgress", luar.New(L, io.ErrNoProgress)) L.SetField(pkg, "ErrShortBuffer", luar.New(L, io.ErrShortBuffer)) L.SetField(pkg, "ErrShortWrite", luar.New(L, io.ErrShortWrite)) L.SetField(pkg, "ErrUnexpectedEOF", luar.New(L, io.ErrUnexpectedEOF)) L.SetField(pkg, "LimitReader", luar.New(L, io.LimitReader)) L.SetField(pkg, "MultiReader", luar.New(L, io.MultiReader)) L.SetField(pkg, "MultiWriter", luar.New(L, io.MultiWriter)) L.SetField(pkg, "NewSectionReader", luar.New(L, io.NewSectionReader)) L.SetField(pkg, "Pipe", luar.New(L, io.Pipe)) L.SetField(pkg, "ReadAll", luar.New(L, io.ReadAll)) L.SetField(pkg, "ReadAtLeast", luar.New(L, io.ReadAtLeast)) L.SetField(pkg, "ReadFull", luar.New(L, io.ReadFull)) L.SetField(pkg, "TeeReader", luar.New(L, io.TeeReader)) L.SetField(pkg, "WriteString", luar.New(L, io.WriteString)) return pkg } func importIoUtil() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "ReadAll", luar.New(L, ioutil.ReadAll)) L.SetField(pkg, "ReadDir", luar.New(L, ioutil.ReadDir)) L.SetField(pkg, "ReadFile", luar.New(L, ioutil.ReadFile)) L.SetField(pkg, "WriteFile", luar.New(L, ioutil.WriteFile)) return pkg } func importNet() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "CIDRMask", luar.New(L, net.CIDRMask)) L.SetField(pkg, "Dial", luar.New(L, net.Dial)) L.SetField(pkg, "DialIP", luar.New(L, net.DialIP)) L.SetField(pkg, "DialTCP", luar.New(L, net.DialTCP)) L.SetField(pkg, "DialTimeout", luar.New(L, net.DialTimeout)) L.SetField(pkg, "DialUDP", luar.New(L, net.DialUDP)) L.SetField(pkg, "DialUnix", luar.New(L, net.DialUnix)) L.SetField(pkg, "ErrWriteToConnected", luar.New(L, net.ErrWriteToConnected)) L.SetField(pkg, "FileConn", luar.New(L, net.FileConn)) L.SetField(pkg, "FileListener", luar.New(L, net.FileListener)) L.SetField(pkg, "FilePacketConn", luar.New(L, net.FilePacketConn)) L.SetField(pkg, "FlagBroadcast", luar.New(L, net.FlagBroadcast)) L.SetField(pkg, "FlagLoopback", luar.New(L, net.FlagLoopback)) L.SetField(pkg, "FlagMulticast", luar.New(L, net.FlagMulticast)) L.SetField(pkg, "FlagPointToPoint", luar.New(L, net.FlagPointToPoint)) L.SetField(pkg, "FlagUp", luar.New(L, net.FlagUp)) L.SetField(pkg, "IPv4", luar.New(L, net.IPv4)) L.SetField(pkg, "IPv4Mask", luar.New(L, net.IPv4Mask)) L.SetField(pkg, "IPv4allrouter", luar.New(L, net.IPv4allrouter)) L.SetField(pkg, "IPv4allsys", luar.New(L, net.IPv4allsys)) L.SetField(pkg, "IPv4bcast", luar.New(L, net.IPv4bcast)) L.SetField(pkg, "IPv4len", luar.New(L, net.IPv4len)) L.SetField(pkg, "IPv4zero", luar.New(L, net.IPv4zero)) L.SetField(pkg, "IPv6interfacelocalallnodes", luar.New(L, net.IPv6interfacelocalallnodes)) L.SetField(pkg, "IPv6len", luar.New(L, net.IPv6len)) L.SetField(pkg, "IPv6linklocalallnodes", luar.New(L, net.IPv6linklocalallnodes)) L.SetField(pkg, "IPv6linklocalallrouters", luar.New(L, net.IPv6linklocalallrouters)) L.SetField(pkg, "IPv6loopback", luar.New(L, net.IPv6loopback)) L.SetField(pkg, "IPv6unspecified", luar.New(L, net.IPv6unspecified)) L.SetField(pkg, "IPv6zero", luar.New(L, net.IPv6zero)) L.SetField(pkg, "InterfaceAddrs", luar.New(L, net.InterfaceAddrs)) L.SetField(pkg, "InterfaceByIndex", luar.New(L, net.InterfaceByIndex)) L.SetField(pkg, "InterfaceByName", luar.New(L, net.InterfaceByName)) L.SetField(pkg, "Interfaces", luar.New(L, net.Interfaces)) L.SetField(pkg, "JoinHostPort", luar.New(L, net.JoinHostPort)) L.SetField(pkg, "Listen", luar.New(L, net.Listen)) L.SetField(pkg, "ListenIP", luar.New(L, net.ListenIP)) L.SetField(pkg, "ListenMulticastUDP", luar.New(L, net.ListenMulticastUDP)) L.SetField(pkg, "ListenPacket", luar.New(L, net.ListenPacket)) L.SetField(pkg, "ListenTCP", luar.New(L, net.ListenTCP)) L.SetField(pkg, "ListenUDP", luar.New(L, net.ListenUDP)) L.SetField(pkg, "ListenUnix", luar.New(L, net.ListenUnix)) L.SetField(pkg, "ListenUnixgram", luar.New(L, net.ListenUnixgram)) L.SetField(pkg, "LookupAddr", luar.New(L, net.LookupAddr)) L.SetField(pkg, "LookupCNAME", luar.New(L, net.LookupCNAME)) L.SetField(pkg, "LookupHost", luar.New(L, net.LookupHost)) L.SetField(pkg, "LookupIP", luar.New(L, net.LookupIP)) L.SetField(pkg, "LookupMX", luar.New(L, net.LookupMX)) L.SetField(pkg, "LookupNS", luar.New(L, net.LookupNS)) L.SetField(pkg, "LookupPort", luar.New(L, net.LookupPort)) L.SetField(pkg, "LookupSRV", luar.New(L, net.LookupSRV)) L.SetField(pkg, "LookupTXT", luar.New(L, net.LookupTXT)) L.SetField(pkg, "ParseCIDR", luar.New(L, net.ParseCIDR)) L.SetField(pkg, "ParseIP", luar.New(L, net.ParseIP)) L.SetField(pkg, "ParseMAC", luar.New(L, net.ParseMAC)) L.SetField(pkg, "Pipe", luar.New(L, net.Pipe)) L.SetField(pkg, "ResolveIPAddr", luar.New(L, net.ResolveIPAddr)) L.SetField(pkg, "ResolveTCPAddr", luar.New(L, net.ResolveTCPAddr)) L.SetField(pkg, "ResolveUDPAddr", luar.New(L, net.ResolveUDPAddr)) L.SetField(pkg, "ResolveUnixAddr", luar.New(L, net.ResolveUnixAddr)) L.SetField(pkg, "SplitHostPort", luar.New(L, net.SplitHostPort)) return pkg } func importMath() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Abs", luar.New(L, math.Abs)) L.SetField(pkg, "Acos", luar.New(L, math.Acos)) L.SetField(pkg, "Acosh", luar.New(L, math.Acosh)) L.SetField(pkg, "Asin", luar.New(L, math.Asin)) L.SetField(pkg, "Asinh", luar.New(L, math.Asinh)) L.SetField(pkg, "Atan", luar.New(L, math.Atan)) L.SetField(pkg, "Atan2", luar.New(L, math.Atan2)) L.SetField(pkg, "Atanh", luar.New(L, math.Atanh)) L.SetField(pkg, "Cbrt", luar.New(L, math.Cbrt)) L.SetField(pkg, "Ceil", luar.New(L, math.Ceil)) L.SetField(pkg, "Copysign", luar.New(L, math.Copysign)) L.SetField(pkg, "Cos", luar.New(L, math.Cos)) L.SetField(pkg, "Cosh", luar.New(L, math.Cosh)) L.SetField(pkg, "Dim", luar.New(L, math.Dim)) L.SetField(pkg, "Erf", luar.New(L, math.Erf)) L.SetField(pkg, "Erfc", luar.New(L, math.Erfc)) L.SetField(pkg, "Exp", luar.New(L, math.Exp)) L.SetField(pkg, "Exp2", luar.New(L, math.Exp2)) L.SetField(pkg, "Expm1", luar.New(L, math.Expm1)) L.SetField(pkg, "Float32bits", luar.New(L, math.Float32bits)) L.SetField(pkg, "Float32frombits", luar.New(L, math.Float32frombits)) L.SetField(pkg, "Float64bits", luar.New(L, math.Float64bits)) L.SetField(pkg, "Float64frombits", luar.New(L, math.Float64frombits)) L.SetField(pkg, "Floor", luar.New(L, math.Floor)) L.SetField(pkg, "Frexp", luar.New(L, math.Frexp)) L.SetField(pkg, "Gamma", luar.New(L, math.Gamma)) L.SetField(pkg, "Hypot", luar.New(L, math.Hypot)) L.SetField(pkg, "Ilogb", luar.New(L, math.Ilogb)) L.SetField(pkg, "Inf", luar.New(L, math.Inf)) L.SetField(pkg, "IsInf", luar.New(L, math.IsInf)) L.SetField(pkg, "IsNaN", luar.New(L, math.IsNaN)) L.SetField(pkg, "J0", luar.New(L, math.J0)) L.SetField(pkg, "J1", luar.New(L, math.J1)) L.SetField(pkg, "Jn", luar.New(L, math.Jn)) L.SetField(pkg, "Ldexp", luar.New(L, math.Ldexp)) L.SetField(pkg, "Lgamma", luar.New(L, math.Lgamma)) L.SetField(pkg, "Log", luar.New(L, math.Log)) L.SetField(pkg, "Log10", luar.New(L, math.Log10)) L.SetField(pkg, "Log1p", luar.New(L, math.Log1p)) L.SetField(pkg, "Log2", luar.New(L, math.Log2)) L.SetField(pkg, "Logb", luar.New(L, math.Logb)) L.SetField(pkg, "Max", luar.New(L, math.Max)) L.SetField(pkg, "Min", luar.New(L, math.Min)) L.SetField(pkg, "Mod", luar.New(L, math.Mod)) L.SetField(pkg, "Modf", luar.New(L, math.Modf)) L.SetField(pkg, "NaN", luar.New(L, math.NaN)) L.SetField(pkg, "Nextafter", luar.New(L, math.Nextafter)) L.SetField(pkg, "Pow", luar.New(L, math.Pow)) L.SetField(pkg, "Pow10", luar.New(L, math.Pow10)) L.SetField(pkg, "Remainder", luar.New(L, math.Remainder)) L.SetField(pkg, "Signbit", luar.New(L, math.Signbit)) L.SetField(pkg, "Sin", luar.New(L, math.Sin)) L.SetField(pkg, "Sincos", luar.New(L, math.Sincos)) L.SetField(pkg, "Sinh", luar.New(L, math.Sinh)) L.SetField(pkg, "Sqrt", luar.New(L, math.Sqrt)) L.SetField(pkg, "Tan", luar.New(L, math.Tan)) L.SetField(pkg, "Tanh", luar.New(L, math.Tanh)) L.SetField(pkg, "Trunc", luar.New(L, math.Trunc)) L.SetField(pkg, "Y0", luar.New(L, math.Y0)) L.SetField(pkg, "Y1", luar.New(L, math.Y1)) L.SetField(pkg, "Yn", luar.New(L, math.Yn)) return pkg } func importMathRand() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "ExpFloat64", luar.New(L, rand.ExpFloat64)) L.SetField(pkg, "Float32", luar.New(L, rand.Float32)) L.SetField(pkg, "Float64", luar.New(L, rand.Float64)) L.SetField(pkg, "Int", luar.New(L, rand.Int)) L.SetField(pkg, "Int31", luar.New(L, rand.Int31)) L.SetField(pkg, "Int31n", luar.New(L, rand.Int31n)) L.SetField(pkg, "Int63", luar.New(L, rand.Int63)) L.SetField(pkg, "Int63n", luar.New(L, rand.Int63n)) L.SetField(pkg, "Intn", luar.New(L, rand.Intn)) L.SetField(pkg, "NormFloat64", luar.New(L, rand.NormFloat64)) L.SetField(pkg, "Perm", luar.New(L, rand.Perm)) L.SetField(pkg, "Seed", luar.New(L, rand.Seed)) L.SetField(pkg, "Uint32", luar.New(L, rand.Uint32)) return pkg } func importOs() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Args", luar.New(L, os.Args)) L.SetField(pkg, "Chdir", luar.New(L, os.Chdir)) L.SetField(pkg, "Chmod", luar.New(L, os.Chmod)) L.SetField(pkg, "Chown", luar.New(L, os.Chown)) L.SetField(pkg, "Chtimes", luar.New(L, os.Chtimes)) L.SetField(pkg, "Clearenv", luar.New(L, os.Clearenv)) L.SetField(pkg, "Create", luar.New(L, os.Create)) L.SetField(pkg, "DevNull", luar.New(L, os.DevNull)) L.SetField(pkg, "Environ", luar.New(L, os.Environ)) L.SetField(pkg, "ErrExist", luar.New(L, os.ErrExist)) L.SetField(pkg, "ErrInvalid", luar.New(L, os.ErrInvalid)) L.SetField(pkg, "ErrNotExist", luar.New(L, os.ErrNotExist)) L.SetField(pkg, "ErrPermission", luar.New(L, os.ErrPermission)) L.SetField(pkg, "Exit", luar.New(L, os.Exit)) L.SetField(pkg, "Expand", luar.New(L, os.Expand)) L.SetField(pkg, "ExpandEnv", luar.New(L, os.ExpandEnv)) L.SetField(pkg, "FindProcess", luar.New(L, os.FindProcess)) L.SetField(pkg, "Getegid", luar.New(L, os.Getegid)) L.SetField(pkg, "Getenv", luar.New(L, os.Getenv)) L.SetField(pkg, "Geteuid", luar.New(L, os.Geteuid)) L.SetField(pkg, "Getgid", luar.New(L, os.Getgid)) L.SetField(pkg, "Getgroups", luar.New(L, os.Getgroups)) L.SetField(pkg, "Getpagesize", luar.New(L, os.Getpagesize)) L.SetField(pkg, "Getpid", luar.New(L, os.Getpid)) L.SetField(pkg, "Getuid", luar.New(L, os.Getuid)) L.SetField(pkg, "Getwd", luar.New(L, os.Getwd)) L.SetField(pkg, "Hostname", luar.New(L, os.Hostname)) L.SetField(pkg, "Interrupt", luar.New(L, os.Interrupt)) L.SetField(pkg, "IsExist", luar.New(L, os.IsExist)) L.SetField(pkg, "IsNotExist", luar.New(L, os.IsNotExist)) L.SetField(pkg, "IsPathSeparator", luar.New(L, os.IsPathSeparator)) L.SetField(pkg, "IsPermission", luar.New(L, os.IsPermission)) L.SetField(pkg, "Kill", luar.New(L, os.Kill)) L.SetField(pkg, "Lchown", luar.New(L, os.Lchown)) L.SetField(pkg, "Link", luar.New(L, os.Link)) L.SetField(pkg, "Lstat", luar.New(L, os.Lstat)) L.SetField(pkg, "Mkdir", luar.New(L, os.Mkdir)) L.SetField(pkg, "MkdirAll", luar.New(L, os.MkdirAll)) L.SetField(pkg, "ModeAppend", luar.New(L, os.ModeAppend)) L.SetField(pkg, "ModeCharDevice", luar.New(L, os.ModeCharDevice)) L.SetField(pkg, "ModeDevice", luar.New(L, os.ModeDevice)) L.SetField(pkg, "ModeDir", luar.New(L, os.ModeDir)) L.SetField(pkg, "ModeExclusive", luar.New(L, os.ModeExclusive)) L.SetField(pkg, "ModeNamedPipe", luar.New(L, os.ModeNamedPipe)) L.SetField(pkg, "ModePerm", luar.New(L, os.ModePerm)) L.SetField(pkg, "ModeSetgid", luar.New(L, os.ModeSetgid)) L.SetField(pkg, "ModeSetuid", luar.New(L, os.ModeSetuid)) L.SetField(pkg, "ModeSocket", luar.New(L, os.ModeSocket)) L.SetField(pkg, "ModeSticky", luar.New(L, os.ModeSticky)) L.SetField(pkg, "ModeSymlink", luar.New(L, os.ModeSymlink)) L.SetField(pkg, "ModeTemporary", luar.New(L, os.ModeTemporary)) L.SetField(pkg, "ModeType", luar.New(L, os.ModeType)) L.SetField(pkg, "NewFile", luar.New(L, os.NewFile)) L.SetField(pkg, "NewSyscallError", luar.New(L, os.NewSyscallError)) L.SetField(pkg, "O_APPEND", luar.New(L, os.O_APPEND)) L.SetField(pkg, "O_CREATE", luar.New(L, os.O_CREATE)) L.SetField(pkg, "O_EXCL", luar.New(L, os.O_EXCL)) L.SetField(pkg, "O_RDONLY", luar.New(L, os.O_RDONLY)) L.SetField(pkg, "O_RDWR", luar.New(L, os.O_RDWR)) L.SetField(pkg, "O_SYNC", luar.New(L, os.O_SYNC)) L.SetField(pkg, "O_TRUNC", luar.New(L, os.O_TRUNC)) L.SetField(pkg, "O_WRONLY", luar.New(L, os.O_WRONLY)) L.SetField(pkg, "Open", luar.New(L, os.Open)) L.SetField(pkg, "OpenFile", luar.New(L, os.OpenFile)) L.SetField(pkg, "PathListSeparator", luar.New(L, os.PathListSeparator)) L.SetField(pkg, "PathSeparator", luar.New(L, os.PathSeparator)) L.SetField(pkg, "Pipe", luar.New(L, os.Pipe)) L.SetField(pkg, "ReadDir", luar.New(L, os.ReadDir)) L.SetField(pkg, "ReadFile", luar.New(L, os.ReadFile)) L.SetField(pkg, "Readlink", luar.New(L, os.Readlink)) L.SetField(pkg, "Remove", luar.New(L, os.Remove)) L.SetField(pkg, "RemoveAll", luar.New(L, os.RemoveAll)) L.SetField(pkg, "Rename", luar.New(L, os.Rename)) L.SetField(pkg, "SEEK_CUR", luar.New(L, io.SeekCurrent)) L.SetField(pkg, "SEEK_END", luar.New(L, io.SeekEnd)) L.SetField(pkg, "SEEK_SET", luar.New(L, io.SeekStart)) L.SetField(pkg, "SameFile", luar.New(L, os.SameFile)) L.SetField(pkg, "Setenv", luar.New(L, os.Setenv)) L.SetField(pkg, "StartProcess", luar.New(L, os.StartProcess)) L.SetField(pkg, "Stat", luar.New(L, os.Stat)) L.SetField(pkg, "Stderr", luar.New(L, os.Stderr)) L.SetField(pkg, "Stdin", luar.New(L, os.Stdin)) L.SetField(pkg, "Stdout", luar.New(L, os.Stdout)) L.SetField(pkg, "Symlink", luar.New(L, os.Symlink)) L.SetField(pkg, "TempDir", luar.New(L, os.TempDir)) L.SetField(pkg, "Truncate", luar.New(L, os.Truncate)) L.SetField(pkg, "UserHomeDir", luar.New(L, os.UserHomeDir)) L.SetField(pkg, "WriteFile", luar.New(L, os.WriteFile)) return pkg } func importRuntime() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "GC", luar.New(L, runtime.GC)) L.SetField(pkg, "GOARCH", luar.New(L, runtime.GOARCH)) L.SetField(pkg, "GOMAXPROCS", luar.New(L, runtime.GOMAXPROCS)) L.SetField(pkg, "GOOS", luar.New(L, runtime.GOOS)) L.SetField(pkg, "GOROOT", luar.New(L, runtime.GOROOT)) return pkg } func importPath() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Base", luar.New(L, path.Base)) L.SetField(pkg, "Clean", luar.New(L, path.Clean)) L.SetField(pkg, "Dir", luar.New(L, path.Dir)) L.SetField(pkg, "ErrBadPattern", luar.New(L, path.ErrBadPattern)) L.SetField(pkg, "Ext", luar.New(L, path.Ext)) L.SetField(pkg, "IsAbs", luar.New(L, path.IsAbs)) L.SetField(pkg, "Join", luar.New(L, path.Join)) L.SetField(pkg, "Match", luar.New(L, path.Match)) L.SetField(pkg, "Split", luar.New(L, path.Split)) return pkg } func importFilePath() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Abs", luar.New(L, filepath.Abs)) L.SetField(pkg, "Base", luar.New(L, filepath.Base)) L.SetField(pkg, "Clean", luar.New(L, filepath.Clean)) L.SetField(pkg, "Dir", luar.New(L, filepath.Dir)) L.SetField(pkg, "EvalSymlinks", luar.New(L, filepath.EvalSymlinks)) L.SetField(pkg, "Ext", luar.New(L, filepath.Ext)) L.SetField(pkg, "FromSlash", luar.New(L, filepath.FromSlash)) L.SetField(pkg, "Glob", luar.New(L, filepath.Glob)) L.SetField(pkg, "HasPrefix", luar.New(L, filepath.HasPrefix)) L.SetField(pkg, "IsAbs", luar.New(L, filepath.IsAbs)) L.SetField(pkg, "Join", luar.New(L, filepath.Join)) L.SetField(pkg, "Match", luar.New(L, filepath.Match)) L.SetField(pkg, "Rel", luar.New(L, filepath.Rel)) L.SetField(pkg, "Split", luar.New(L, filepath.Split)) L.SetField(pkg, "SplitList", luar.New(L, filepath.SplitList)) L.SetField(pkg, "ToSlash", luar.New(L, filepath.ToSlash)) L.SetField(pkg, "VolumeName", luar.New(L, filepath.VolumeName)) return pkg } func importStrings() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Contains", luar.New(L, strings.Contains)) L.SetField(pkg, "ContainsAny", luar.New(L, strings.ContainsAny)) L.SetField(pkg, "ContainsRune", luar.New(L, strings.ContainsRune)) L.SetField(pkg, "Count", luar.New(L, strings.Count)) L.SetField(pkg, "EqualFold", luar.New(L, strings.EqualFold)) L.SetField(pkg, "Fields", luar.New(L, strings.Fields)) L.SetField(pkg, "FieldsFunc", luar.New(L, strings.FieldsFunc)) L.SetField(pkg, "HasPrefix", luar.New(L, strings.HasPrefix)) L.SetField(pkg, "HasSuffix", luar.New(L, strings.HasSuffix)) L.SetField(pkg, "Index", luar.New(L, strings.Index)) L.SetField(pkg, "IndexAny", luar.New(L, strings.IndexAny)) L.SetField(pkg, "IndexByte", luar.New(L, strings.IndexByte)) L.SetField(pkg, "IndexFunc", luar.New(L, strings.IndexFunc)) L.SetField(pkg, "IndexRune", luar.New(L, strings.IndexRune)) L.SetField(pkg, "Join", luar.New(L, strings.Join)) L.SetField(pkg, "LastIndex", luar.New(L, strings.LastIndex)) L.SetField(pkg, "LastIndexAny", luar.New(L, strings.LastIndexAny)) L.SetField(pkg, "LastIndexFunc", luar.New(L, strings.LastIndexFunc)) L.SetField(pkg, "Map", luar.New(L, strings.Map)) L.SetField(pkg, "NewReader", luar.New(L, strings.NewReader)) L.SetField(pkg, "NewReplacer", luar.New(L, strings.NewReplacer)) L.SetField(pkg, "Repeat", luar.New(L, strings.Repeat)) L.SetField(pkg, "Replace", luar.New(L, strings.Replace)) L.SetField(pkg, "Split", luar.New(L, strings.Split)) L.SetField(pkg, "SplitAfter", luar.New(L, strings.SplitAfter)) L.SetField(pkg, "SplitAfterN", luar.New(L, strings.SplitAfterN)) L.SetField(pkg, "SplitN", luar.New(L, strings.SplitN)) L.SetField(pkg, "Title", luar.New(L, strings.Title)) L.SetField(pkg, "ToLower", luar.New(L, strings.ToLower)) L.SetField(pkg, "ToLowerSpecial", luar.New(L, strings.ToLowerSpecial)) L.SetField(pkg, "ToTitle", luar.New(L, strings.ToTitle)) L.SetField(pkg, "ToTitleSpecial", luar.New(L, strings.ToTitleSpecial)) L.SetField(pkg, "ToUpper", luar.New(L, strings.ToUpper)) L.SetField(pkg, "ToUpperSpecial", luar.New(L, strings.ToUpperSpecial)) L.SetField(pkg, "Trim", luar.New(L, strings.Trim)) L.SetField(pkg, "TrimFunc", luar.New(L, strings.TrimFunc)) L.SetField(pkg, "TrimLeft", luar.New(L, strings.TrimLeft)) L.SetField(pkg, "TrimLeftFunc", luar.New(L, strings.TrimLeftFunc)) L.SetField(pkg, "TrimPrefix", luar.New(L, strings.TrimPrefix)) L.SetField(pkg, "TrimRight", luar.New(L, strings.TrimRight)) L.SetField(pkg, "TrimRightFunc", luar.New(L, strings.TrimRightFunc)) L.SetField(pkg, "TrimSpace", luar.New(L, strings.TrimSpace)) L.SetField(pkg, "TrimSuffix", luar.New(L, strings.TrimSuffix)) return pkg } func importRegexp() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Match", luar.New(L, regexp.Match)) L.SetField(pkg, "MatchReader", luar.New(L, regexp.MatchReader)) L.SetField(pkg, "MatchString", luar.New(L, regexp.MatchString)) L.SetField(pkg, "QuoteMeta", luar.New(L, regexp.QuoteMeta)) L.SetField(pkg, "Compile", luar.New(L, regexp.Compile)) L.SetField(pkg, "CompilePOSIX", luar.New(L, regexp.CompilePOSIX)) L.SetField(pkg, "MustCompile", luar.New(L, regexp.MustCompile)) L.SetField(pkg, "MustCompilePOSIX", luar.New(L, regexp.MustCompilePOSIX)) return pkg } func importErrors() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "New", luar.New(L, errors.New)) return pkg } func importTime() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Sleep", luar.New(L, time.Sleep)) L.SetField(pkg, "Since", luar.New(L, time.Since)) L.SetField(pkg, "FixedZone", luar.New(L, time.FixedZone)) L.SetField(pkg, "LoadLocation", luar.New(L, time.LoadLocation)) L.SetField(pkg, "Date", luar.New(L, time.Date)) L.SetField(pkg, "Now", luar.New(L, time.Now)) L.SetField(pkg, "Parse", luar.New(L, time.Parse)) L.SetField(pkg, "ParseDuration", luar.New(L, time.ParseDuration)) L.SetField(pkg, "ParseInLocation", luar.New(L, time.ParseInLocation)) L.SetField(pkg, "Unix", luar.New(L, time.Unix)) L.SetField(pkg, "Nanosecond", luar.New(L, time.Nanosecond)) L.SetField(pkg, "Microsecond", luar.New(L, time.Microsecond)) L.SetField(pkg, "Millisecond", luar.New(L, time.Millisecond)) L.SetField(pkg, "Second", luar.New(L, time.Second)) L.SetField(pkg, "Minute", luar.New(L, time.Minute)) L.SetField(pkg, "Hour", luar.New(L, time.Hour)) // TODO: these raw Go timer APIs don't provide any synchronization // with micro. Stop exposing them to lua once plugins switch to using // the safer micro.After() interface instead. See issue #3209 L.SetField(pkg, "After", luar.New(L, time.After)) L.SetField(pkg, "AfterFunc", luar.New(L, time.AfterFunc)) L.SetField(pkg, "NewTicker", luar.New(L, time.NewTicker)) L.SetField(pkg, "NewTimer", luar.New(L, time.NewTimer)) L.SetField(pkg, "Tick", luar.New(L, time.Tick)) return pkg } func importUtf8() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "DecodeLastRune", luar.New(L, utf8.DecodeLastRune)) L.SetField(pkg, "DecodeLastRuneInString", luar.New(L, utf8.DecodeLastRuneInString)) L.SetField(pkg, "DecodeRune", luar.New(L, utf8.DecodeRune)) L.SetField(pkg, "DecodeRuneInString", luar.New(L, utf8.DecodeRuneInString)) L.SetField(pkg, "EncodeRune", luar.New(L, utf8.EncodeRune)) L.SetField(pkg, "FullRune", luar.New(L, utf8.FullRune)) L.SetField(pkg, "FullRuneInString", luar.New(L, utf8.FullRuneInString)) L.SetField(pkg, "RuneCount", luar.New(L, utf8.RuneCount)) L.SetField(pkg, "RuneCountInString", luar.New(L, utf8.RuneCountInString)) L.SetField(pkg, "RuneLen", luar.New(L, utf8.RuneLen)) L.SetField(pkg, "RuneStart", luar.New(L, utf8.RuneStart)) L.SetField(pkg, "Valid", luar.New(L, utf8.Valid)) L.SetField(pkg, "ValidRune", luar.New(L, utf8.ValidRune)) L.SetField(pkg, "ValidString", luar.New(L, utf8.ValidString)) return pkg } func importHumanize() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Bytes", luar.New(L, humanize.Bytes)) L.SetField(pkg, "Ordinal", luar.New(L, humanize.Ordinal)) return pkg } func importHTTP() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "Get", luar.New(L, http.Get)) L.SetField(pkg, "Post", luar.New(L, http.Post)) return pkg } func importArchiveZip() *lua.LTable { pkg := L.NewTable() L.SetField(pkg, "OpenReader", luar.New(L, zip.OpenReader)) L.SetField(pkg, "NewReader", luar.New(L, zip.NewReader)) L.SetField(pkg, "NewWriter", luar.New(L, zip.NewWriter)) return pkg } zyedidia-micro-6a62575/internal/info/0000775000175000017510000000000015125206537017012 5ustar nileshnileshzyedidia-micro-6a62575/internal/info/infobuffer.go0000664000175000017510000001133215125206537021466 0ustar nileshnileshpackage info import ( "fmt" "github.com/zyedidia/micro/v2/internal/buffer" ) // The InfoBuf displays messages and other info at the bottom of the screen. // It is represented as a buffer and a message with a style. type InfoBuf struct { *buffer.Buffer HasPrompt bool HasMessage bool HasError bool HasYN bool PromptType string Msg string YNResp bool // This map stores the history for all the different kinds of uses Prompt has // It's a map of history type -> history array History map[string][]string HistoryNum int // HistorySearch indicates whether we are searching for history items // beginning with HistorySearchPrefix HistorySearch bool HistorySearchPrefix string // Is the current message a message from the gutter HasGutter bool PromptCallback func(resp string, canceled bool) EventCallback func(resp string) YNCallback func(yes bool, canceled bool) } // NewBuffer returns a new infobuffer func NewBuffer() *InfoBuf { ib := new(InfoBuf) ib.History = make(map[string][]string) ib.Buffer = buffer.NewBufferFromString("", "", buffer.BTInfo) ib.LoadHistory() return ib } // Close performs any cleanup necessary when shutting down the infobuffer func (i *InfoBuf) Close() { i.SaveHistory() } // Message sends a message to the user func (i *InfoBuf) Message(msg ...any) { // only display a new message if there isn't an active prompt // this is to prevent overwriting an existing prompt to the user if !i.HasPrompt { displayMessage := fmt.Sprint(msg...) // if there is no active prompt then style and display the message as normal i.Msg = displayMessage i.HasMessage, i.HasError = true, false } } // GutterMessage displays a message and marks it as a gutter message func (i *InfoBuf) GutterMessage(msg ...any) { i.Message(msg...) i.HasGutter = true } // ClearGutter clears the info bar and unmarks the message func (i *InfoBuf) ClearGutter() { i.HasGutter = false i.Message("") } // Error sends an error message to the user func (i *InfoBuf) Error(msg ...any) { // only display a new message if there isn't an active prompt // this is to prevent overwriting an existing prompt to the user if !i.HasPrompt { // if there is no active prompt then style and display the message as normal i.Msg = fmt.Sprint(msg...) i.HasMessage, i.HasError = false, true } // TODO: add to log? } // Prompt starts a prompt for the user, it takes a prompt, a possibly partially filled in msg // and callbacks executed when the user executes an event and when the user finishes the prompt // The eventcb passes the current user response as the argument and donecb passes the user's message // and a boolean indicating if the prompt was canceled func (i *InfoBuf) Prompt(prompt string, msg string, ptype string, eventcb func(string), donecb func(string, bool)) { // If we get another prompt mid-prompt we cancel the one getting overwritten if i.HasPrompt { i.DonePrompt(true) } if _, ok := i.History[ptype]; !ok { i.History[ptype] = []string{""} } else { i.History[ptype] = append(i.History[ptype], "") } i.HistoryNum = len(i.History[ptype]) - 1 i.HistorySearch = false i.PromptType = ptype i.Msg = prompt i.HasPrompt = true i.HasMessage, i.HasError, i.HasYN = false, false, false i.HasGutter = false i.PromptCallback = donecb i.EventCallback = eventcb i.Buffer.Insert(i.Buffer.Start(), msg) } // YNPrompt creates a yes or no prompt, and the callback returns the yes/no result and whether // the prompt was canceled func (i *InfoBuf) YNPrompt(prompt string, donecb func(bool, bool)) { if i.HasPrompt { i.DonePrompt(true) } i.Msg = prompt i.HasPrompt = true i.HasYN = true i.HasMessage, i.HasError = false, false i.HasGutter = false i.YNCallback = donecb } // DonePrompt finishes the current prompt and indicates whether or not it was canceled func (i *InfoBuf) DonePrompt(canceled bool) { hadYN := i.HasYN i.HasPrompt = false i.HasYN = false i.HasGutter = false if !hadYN { if i.PromptCallback != nil { if canceled { i.Replace(i.Start(), i.End(), "") h := i.History[i.PromptType] i.History[i.PromptType] = h[:len(h)-1] i.PromptCallback("", true) } else { resp := string(i.LineBytes(0)) i.Replace(i.Start(), i.End(), "") h := i.History[i.PromptType] h[len(h)-1] = resp // avoid duplicates for j := len(h) - 2; j >= 0; j-- { if h[j] == h[len(h)-1] { i.History[i.PromptType] = append(h[:j], h[j+1:]...) break } } i.PromptCallback(resp, false) } // i.PromptCallback = nil } } if i.YNCallback != nil && hadYN { i.YNCallback(i.YNResp, canceled) } } // Reset resets the infobuffer's msg and info func (i *InfoBuf) Reset() { i.Msg = "" i.HasPrompt, i.HasMessage, i.HasError = false, false, false i.HasGutter = false } zyedidia-micro-6a62575/internal/info/history.go0000664000175000017510000001002715125206537021042 0ustar nileshnileshpackage info import ( "bytes" "encoding/gob" "errors" "io/fs" "os" "path/filepath" "strings" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) // LoadHistory attempts to load user history from configDir/buffers/history // into the history map // The savehistory option must be on func (i *InfoBuf) LoadHistory() { if config.GetGlobalOption("savehistory").(bool) { file, err := os.Open(filepath.Join(config.ConfigDir, "buffers", "history")) var decodedMap map[string][]string if err != nil { if !errors.Is(err, fs.ErrNotExist) { i.Error("Error loading history: ", err) } return } defer file.Close() err = gob.NewDecoder(file).Decode(&decodedMap) if err != nil { i.Error("Error decoding history: ", err) return } if decodedMap != nil { i.History = decodedMap } } } // SaveHistory saves the user's command history to configDir/buffers/history // only if the savehistory option is on func (i *InfoBuf) SaveHistory() { if config.GetGlobalOption("savehistory").(bool) { // Don't save history past 100 for k, v := range i.History { if len(v) > 100 { i.History[k] = v[len(i.History[k])-100:] } } var buf bytes.Buffer err := gob.NewEncoder(&buf).Encode(i.History) if err != nil { screen.TermMessage("Error encoding history: ", err) return } filename := filepath.Join(config.ConfigDir, "buffers", "history") err = util.SafeWrite(filename, buf.Bytes(), true) if err != nil { screen.TermMessage("Error saving history: ", err) return } } } // AddToHistory adds a new item to the history for the prompt type `ptype`. // This function is not used by micro itself. It is useful for plugins // which add their own items to the history, bypassing the infobar command line. func (i *InfoBuf) AddToHistory(ptype string, item string) { if i.HasPrompt && i.PromptType == ptype { return } if _, ok := i.History[ptype]; !ok { i.History[ptype] = []string{item} } else { i.History[ptype] = append(i.History[ptype], item) // avoid duplicates h := i.History[ptype] for j := len(h) - 2; j >= 0; j-- { if h[j] == h[len(h)-1] { i.History[ptype] = append(h[:j], h[j+1:]...) break } } } } // UpHistory fetches the previous item in the history func (i *InfoBuf) UpHistory(history []string) { if i.HistoryNum > 0 && i.HasPrompt && !i.HasYN { i.HistoryNum-- i.Replace(i.Start(), i.End(), history[i.HistoryNum]) i.Buffer.GetActiveCursor().GotoLoc(i.End()) } } // DownHistory fetches the next item in the history func (i *InfoBuf) DownHistory(history []string) { if i.HistoryNum < len(history)-1 && i.HasPrompt && !i.HasYN { i.HistoryNum++ i.Replace(i.Start(), i.End(), history[i.HistoryNum]) i.Buffer.GetActiveCursor().GotoLoc(i.End()) } } // SearchUpHistory fetches the previous item in the history // beginning with the text in the infobuffer before cursor func (i *InfoBuf) SearchUpHistory(history []string) { if i.HistoryNum > 0 && i.HasPrompt && !i.HasYN { i.searchHistory(history, false) } } // SearchDownHistory fetches the next item in the history // beginning with the text in the infobuffer before cursor func (i *InfoBuf) SearchDownHistory(history []string) { if i.HistoryNum < len(history)-1 && i.HasPrompt && !i.HasYN { i.searchHistory(history, true) } } func (i *InfoBuf) searchHistory(history []string, down bool) { line := string(i.LineBytes(0)) c := i.Buffer.GetActiveCursor() if !i.HistorySearch || !strings.HasPrefix(line, i.HistorySearchPrefix) { i.HistorySearch = true i.HistorySearchPrefix = util.SliceStartStr(line, c.X) } found := -1 if down { for j := i.HistoryNum + 1; j < len(history); j++ { if strings.HasPrefix(history[j], i.HistorySearchPrefix) { found = j break } } } else { for j := i.HistoryNum - 1; j >= 0; j-- { if strings.HasPrefix(history[j], i.HistorySearchPrefix) { found = j break } } } if found != -1 { i.HistoryNum = found i.Replace(i.Start(), i.End(), history[found]) c.GotoLoc(i.End()) } } zyedidia-micro-6a62575/internal/info/gutter.go0000664000175000017510000000061515125206537020655 0ustar nileshnileshpackage info // A GutterMessage is a message displayed on the side of the editor type GutterMessage struct { lineNum int msg string kind int } // These are the different types of messages const ( // GutterInfo represents a simple info message GutterInfo = iota // GutterWarning represents a compiler warning GutterWarning // GutterError represents a compiler error GutterError ) zyedidia-micro-6a62575/internal/display/0000775000175000017510000000000015125206537017524 5ustar nileshnileshzyedidia-micro-6a62575/internal/display/window.go0000664000175000017510000000140615125206537021363 0ustar nileshnileshpackage display import ( "github.com/zyedidia/micro/v2/internal/buffer" ) type View struct { X, Y int // X,Y location of the view Width, Height int // Width and height of the view // Start line of the view (for vertical scroll) StartLine SLoc // Start column of the view (for horizontal scroll) // note that since the starting column of every line is different if the view // is scrolled, StartCol is a visual index (will be the same for every line) StartCol int } type Window interface { Display() Clear() Relocate() bool GetView() *View SetView(v *View) LocFromVisual(vloc buffer.Loc) buffer.Loc Resize(w, h int) SetActive(b bool) IsActive() bool } type BWindow interface { Window SoftWrap SetBuffer(b *buffer.Buffer) BufView() View } zyedidia-micro-6a62575/internal/display/uiwindow.go0000664000175000017510000000356015125206537021724 0ustar nileshnileshpackage display import ( "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" "github.com/zyedidia/micro/v2/internal/views" ) type UIWindow struct { root *views.Node } func NewUIWindow(n *views.Node) *UIWindow { uw := new(UIWindow) uw.root = n return uw } func (w *UIWindow) drawNode(n *views.Node) { cs := n.Children() dividerStyle := config.DefStyle if style, ok := config.Colorscheme["divider"]; ok { dividerStyle = style } divchars := config.GetGlobalOption("divchars").(string) if util.CharacterCountInString(divchars) != 2 { divchars = "|-" } divchar, combc, _ := util.DecodeCharacterInString(divchars) divreverse := config.GetGlobalOption("divreverse").(bool) if divreverse { dividerStyle = dividerStyle.Reverse(true) } for i, c := range cs { if c.Kind == views.STVert { if i != len(cs)-1 { for h := 0; h < c.H; h++ { screen.SetContent(c.X+c.W, c.Y+h, divchar, combc, dividerStyle) } } } w.drawNode(c) } } func (w *UIWindow) Display() { w.drawNode(w.root) } func (w *UIWindow) GetMouseSplitNode(vloc buffer.Loc) *views.Node { var mouseLoc func(*views.Node) *views.Node mouseLoc = func(n *views.Node) *views.Node { cs := n.Children() for i, c := range cs { if c.Kind == views.STVert { if i != len(cs)-1 { if vloc.X == c.X+c.W && vloc.Y >= c.Y && vloc.Y < c.Y+c.H { return c } } } else if c.Kind == views.STHoriz { if i != len(cs)-1 { if vloc.Y == c.Y+c.H-1 && vloc.X >= c.X && vloc.X < c.X+c.W { return c } } } } for _, c := range cs { m := mouseLoc(c) if m != nil { return m } } return nil } return mouseLoc(w.root) } func (w *UIWindow) Resize(width, height int) {} func (w *UIWindow) SetActive(b bool) {} zyedidia-micro-6a62575/internal/display/termwindow.go0000664000175000017510000000536215125206537022260 0ustar nileshnileshpackage display import ( "github.com/micro-editor/tcell/v2" "github.com/micro-editor/terminal" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/shell" "github.com/zyedidia/micro/v2/internal/util" ) type TermWindow struct { *View *shell.Terminal active bool } func NewTermWindow(x, y, w, h int, term *shell.Terminal) *TermWindow { tw := new(TermWindow) tw.View = new(View) tw.Terminal = term tw.X, tw.Y = x, y tw.Resize(w, h) return tw } // Resize informs the terminal of a resize event func (w *TermWindow) Resize(width, height int) { if config.GetGlobalOption("statusline").(bool) { height-- } w.Term.Resize(width, height) w.Width, w.Height = width, height } func (w *TermWindow) SetActive(b bool) { w.active = b } func (w *TermWindow) IsActive() bool { return w.active } func (w *TermWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc { return vloc } func (w *TermWindow) Clear() { for y := 0; y < w.Height; y++ { for x := 0; x < w.Width; x++ { screen.SetContent(w.X+x, w.Y+y, ' ', nil, config.DefStyle) } } } func (w *TermWindow) Relocate() bool { return true } func (w *TermWindow) GetView() *View { return w.View } func (w *TermWindow) SetView(v *View) { w.View = v } // Display displays this terminal in a view func (w *TermWindow) Display() { w.State.Lock() defer w.State.Unlock() var l buffer.Loc for y := 0; y < w.Height; y++ { for x := 0; x < w.Width; x++ { l.X, l.Y = x, y c, f, b := w.State.Cell(x, y) fg, bg := int(f), int(b) if f == terminal.DefaultFG { fg = int(tcell.ColorDefault) } if b == terminal.DefaultBG { bg = int(tcell.ColorDefault) } st := tcell.StyleDefault.Foreground(config.GetColor256(fg)).Background(config.GetColor256(bg)) if l.LessThan(w.Selection[1]) && l.GreaterEqual(w.Selection[0]) || l.LessThan(w.Selection[0]) && l.GreaterEqual(w.Selection[1]) { st = st.Reverse(true) } screen.SetContent(w.X+x, w.Y+y, c, nil, st) } } if config.GetGlobalOption("statusline").(bool) { statusLineStyle := config.DefStyle.Reverse(true) if style, ok := config.Colorscheme["statusline"]; ok { statusLineStyle = style } text := []byte(w.Name()) textLen := util.CharacterCount(text) for x := 0; x < w.Width; x++ { if x < textLen { r, combc, size := util.DecodeCharacter(text) text = text[size:] screen.SetContent(w.X+x, w.Y+w.Height, r, combc, statusLineStyle) } else { screen.SetContent(w.X+x, w.Y+w.Height, ' ', nil, statusLineStyle) } } } if w.State.CursorVisible() && w.active { curx, cury := w.State.Cursor() if curx < w.Width && cury < w.Height { screen.ShowCursor(curx+w.X, cury+w.Y) } } } zyedidia-micro-6a62575/internal/display/tabwindow.go0000664000175000017510000000703715125206537022060 0ustar nileshnileshpackage display import ( runewidth "github.com/mattn/go-runewidth" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) type TabWindow struct { Names []string active int Y int Width int hscroll int } func NewTabWindow(w int, y int) *TabWindow { tw := new(TabWindow) tw.Width = w tw.Y = y return tw } func (w *TabWindow) Resize(width, height int) { w.Width = width } func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int { x := -w.hscroll for i, n := range w.Names { x++ s := util.CharacterCountInString(n) if vloc.Y == w.Y && vloc.X < x+s { return i } x += s x += 3 if x >= w.Width { break } } return -1 } func (w *TabWindow) Scroll(amt int) { w.hscroll += amt s := w.TotalSize() w.hscroll = util.Clamp(w.hscroll, 0, s-w.Width) if s-w.Width <= 0 { w.hscroll = 0 } } func (w *TabWindow) TotalSize() int { sum := 2 for _, n := range w.Names { sum += runewidth.StringWidth(n) + 4 } return sum - 4 } func (w *TabWindow) Active() int { return w.active } func (w *TabWindow) SetActive(a int) { w.active = a x := 2 s := w.TotalSize() for i, n := range w.Names { c := util.CharacterCountInString(n) if i == a { if x+c >= w.hscroll+w.Width { w.hscroll = util.Clamp(x+c+1-w.Width, 0, s-w.Width) } else if x < w.hscroll { w.hscroll = util.Clamp(x-4, 0, s-w.Width) } break } x += c + 4 } if s-w.Width <= 0 { w.hscroll = 0 } } func (w *TabWindow) Display() { x := -w.hscroll done := false globalTabReverse := config.GetGlobalOption("tabreverse").(bool) globalTabHighlight := config.GetGlobalOption("tabhighlight").(bool) // xor of reverse and tab highlight to get tab character (as in filename and surrounding characters) reverse state tabCharHighlight := (globalTabReverse || globalTabHighlight) && !(globalTabReverse && globalTabHighlight) reverseStyles := func(reverse bool) (tcell.Style, tcell.Style) { tabBarStyle := config.DefStyle.Reverse(reverse) if style, ok := config.Colorscheme["tabbar"]; ok { tabBarStyle = style } tabBarActiveStyle := tabBarStyle if style, ok := config.Colorscheme["tabbar.active"]; ok { tabBarActiveStyle = style } return tabBarStyle, tabBarActiveStyle } draw := func(r rune, n int, active bool, reversed bool) { tabBarStyle, tabBarActiveStyle := reverseStyles(reversed) style := tabBarStyle if active { style = tabBarActiveStyle } for i := 0; i < n; i++ { rw := runewidth.RuneWidth(r) for j := 0; j < rw; j++ { c := r if j > 0 { c = ' ' } if x == w.Width-1 && !done { screen.SetContent(w.Width-1, w.Y, '>', nil, tabBarStyle) x++ break } else if x == 0 && w.hscroll > 0 { screen.SetContent(0, w.Y, '<', nil, tabBarStyle) } else if x >= 0 && x < w.Width { screen.SetContent(x, w.Y, c, nil, style) } x++ } } } for i, n := range w.Names { if i == w.active { draw('[', 1, true, tabCharHighlight) } else { draw(' ', 1, false, tabCharHighlight) } for _, c := range n { draw(c, 1, i == w.active, tabCharHighlight) } if i == len(w.Names)-1 { done = true } if i == w.active { draw(']', 1, true, tabCharHighlight) draw(' ', 2, true, globalTabReverse) } else { draw(' ', 1, false, tabCharHighlight) draw(' ', 2, false, globalTabReverse) } if x >= w.Width { break } } if x < w.Width { draw(' ', w.Width-x, false, globalTabReverse) } } zyedidia-micro-6a62575/internal/display/statusline.go0000664000175000017510000001267215125206537022256 0ustar nileshnileshpackage display import ( "bytes" "fmt" "regexp" "strconv" "strings" luar "layeh.com/gopher-luar" runewidth "github.com/mattn/go-runewidth" lua "github.com/yuin/gopher-lua" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" ulua "github.com/zyedidia/micro/v2/internal/lua" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) // StatusLine represents the information line at the bottom // of each window // It gives information such as filename, whether the file has been // modified, filetype, cursor location type StatusLine struct { Info map[string]func(*buffer.Buffer) string win *BufWindow } var statusInfo = map[string]func(*buffer.Buffer) string{ "filename": func(b *buffer.Buffer) string { return b.GetName() }, "line": func(b *buffer.Buffer) string { return strconv.Itoa(b.GetActiveCursor().Y + 1) }, "col": func(b *buffer.Buffer) string { return strconv.Itoa(b.GetActiveCursor().X + 1) }, "modified": func(b *buffer.Buffer) string { if b.Modified() { return "+ " } if b.Type.Readonly { return "[ro] " } return "" }, "overwrite": func(b *buffer.Buffer) string { if b.OverwriteMode && !b.Type.Readonly { return "[ovwr] " } return "" }, "lines": func(b *buffer.Buffer) string { return strconv.Itoa(b.LinesNum()) }, "percentage": func(b *buffer.Buffer) string { return strconv.Itoa((b.GetActiveCursor().Y + 1) * 100 / b.LinesNum()) }, } func SetStatusInfoFnLua(fn string) { luaFn := strings.Split(fn, ".") if len(luaFn) <= 1 { return } plName, plFn := luaFn[0], luaFn[1] pl := config.FindPlugin(plName) if pl == nil { return } statusInfo[fn] = func(b *buffer.Buffer) string { if pl == nil || !pl.IsLoaded() { return "" } val, err := pl.Call(plFn, luar.New(ulua.L, b)) if err == nil { if v, ok := val.(lua.LString); !ok { screen.TermMessage(plFn, "should return a string") return "" } else { return string(v) } } return "" } } // NewStatusLine returns a statusline bound to a window func NewStatusLine(win *BufWindow) *StatusLine { s := new(StatusLine) s.win = win return s } // FindOpt finds a given option in the current buffer's settings func (s *StatusLine) FindOpt(opt string) any { if val, ok := s.win.Buf.Settings[opt]; ok { return val } return "null" } var formatParser = regexp.MustCompile(`\$\(.+?\)`) // Display draws the statusline to the screen func (s *StatusLine) Display() { // We'll draw the line at the lowest line in the window y := s.win.Height + s.win.Y - 1 winX := s.win.X b := s.win.Buf // autocomplete suggestions (for the buffer, not for the infowindow) if b.HasSuggestions && len(b.Suggestions) > 1 { statusLineStyle := config.DefStyle.Reverse(true) if style, ok := config.Colorscheme["statusline.suggestions"]; ok { statusLineStyle = style } else if style, ok := config.Colorscheme["statusline"]; ok { statusLineStyle = style } x := 0 for j, sug := range b.Suggestions { style := statusLineStyle if b.CurSuggestion == j { style = style.Reverse(true) } for _, r := range sug { screen.SetContent(winX+x, y, r, nil, style) x++ if x >= s.win.Width { return } } screen.SetContent(winX+x, y, ' ', nil, statusLineStyle) x++ if x >= s.win.Width { return } } for x < s.win.Width { screen.SetContent(winX+x, y, ' ', nil, statusLineStyle) x++ } return } formatter := func(match []byte) []byte { name := match[2 : len(match)-1] if bytes.HasPrefix(name, []byte("opt")) { option := name[4:] return fmt.Append(nil, s.FindOpt(string(option))) } else if bytes.HasPrefix(name, []byte("bind")) { binding := string(name[5:]) for k, v := range config.Bindings["buffer"] { if v == binding { return []byte(k) } } return []byte("null") } else { if fn, ok := statusInfo[string(name)]; ok { return []byte(fn(s.win.Buf)) } return []byte{} } } leftText := []byte(s.win.Buf.Settings["statusformatl"].(string)) leftText = formatParser.ReplaceAllFunc(leftText, formatter) rightText := []byte(s.win.Buf.Settings["statusformatr"].(string)) rightText = formatParser.ReplaceAllFunc(rightText, formatter) statusLineStyle := config.DefStyle.Reverse(true) if s.win.IsActive() { if style, ok := config.Colorscheme["statusline"]; ok { statusLineStyle = style } } else { if style, ok := config.Colorscheme["statusline.inactive"]; ok { statusLineStyle = style } else if style, ok := config.Colorscheme["statusline"]; ok { statusLineStyle = style } } leftLen := util.StringWidth(leftText, util.CharacterCount(leftText), 1) rightLen := util.StringWidth(rightText, util.CharacterCount(rightText), 1) for x := 0; x < s.win.Width; x++ { if x < leftLen { r, combc, size := util.DecodeCharacter(leftText) leftText = leftText[size:] rw := runewidth.RuneWidth(r) for j := 0; j < rw; j++ { c := r if j > 0 { c = ' ' combc = nil x++ } screen.SetContent(winX+x, y, c, combc, statusLineStyle) } } else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen { r, combc, size := util.DecodeCharacter(rightText) rightText = rightText[size:] rw := runewidth.RuneWidth(r) for j := 0; j < rw; j++ { c := r if j > 0 { c = ' ' combc = nil x++ } screen.SetContent(winX+x, y, c, combc, statusLineStyle) } } else { screen.SetContent(winX+x, y, ' ', nil, statusLineStyle) } } } zyedidia-micro-6a62575/internal/display/softwrap.go0000664000175000017510000001652015125206537021724 0ustar nileshnileshpackage display import ( runewidth "github.com/mattn/go-runewidth" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/util" ) // SLoc represents a vertical scrolling location, i.e. a location of a visual line // in the buffer. When softwrap is enabled, a buffer line may be displayed as // multiple visual lines (rows). So SLoc stores a number of a line in the buffer // and a number of a row within this line. type SLoc struct { Line, Row int } // LessThan returns true if s is less b func (s SLoc) LessThan(b SLoc) bool { if s.Line < b.Line { return true } return s.Line == b.Line && s.Row < b.Row } // GreaterThan returns true if s is bigger than b func (s SLoc) GreaterThan(b SLoc) bool { if s.Line > b.Line { return true } return s.Line == b.Line && s.Row > b.Row } // LessEqual returns true if s is less than or equal to b func (s SLoc) LessEqual(b SLoc) bool { if s.Line < b.Line { return true } if s.Line == b.Line && s.Row < b.Row { return true } return s == b } // GreaterEqual returns true if s is bigger than or equal to b func (s SLoc) GreaterEqual(b SLoc) bool { if s.Line > b.Line { return true } if s.Line == b.Line && s.Row > b.Row { return true } return s == b } // VLoc represents a location in the buffer as a visual location in the // linewrapped buffer. type VLoc struct { SLoc VisualX int } type SoftWrap interface { Scroll(s SLoc, n int) SLoc Diff(s1, s2 SLoc) int SLocFromLoc(loc buffer.Loc) SLoc VLocFromLoc(loc buffer.Loc) VLoc LocFromVLoc(vloc VLoc) buffer.Loc } func (w *BufWindow) getVLocFromLoc(loc buffer.Loc) VLoc { vloc := VLoc{SLoc: SLoc{loc.Y, 0}, VisualX: 0} if loc.X <= 0 { return vloc } if w.bufWidth <= 0 { return vloc } wordwrap := w.Buf.Settings["wordwrap"].(bool) tabsize := util.IntOpt(w.Buf.Settings["tabsize"]) line := w.Buf.LineBytes(loc.Y) x := 0 totalwidth := 0 wordwidth := 0 wordoffset := 0 for len(line) > 0 { r, _, size := util.DecodeCharacter(line) line = line[size:] width := 0 switch r { case '\t': ts := tabsize - (totalwidth % tabsize) width = util.Min(ts, w.bufWidth-vloc.VisualX) totalwidth += ts default: width = runewidth.RuneWidth(r) totalwidth += width } wordwidth += width // Collect a complete word to know its width. // If wordwrap is off, every single character is a complete "word". if wordwrap { if !util.IsWhitespace(r) && len(line) > 0 && wordwidth < w.bufWidth { if x < loc.X { wordoffset += width x++ } continue } } // If a word (or just a wide rune) does not fit in the window if vloc.VisualX+wordwidth > w.bufWidth && vloc.VisualX > 0 { vloc.Row++ vloc.VisualX = 0 } if x == loc.X { vloc.VisualX += wordoffset return vloc } x++ vloc.VisualX += wordwidth wordwidth = 0 wordoffset = 0 if vloc.VisualX >= w.bufWidth { vloc.Row++ vloc.VisualX = 0 } } return vloc } func (w *BufWindow) getLocFromVLoc(svloc VLoc) buffer.Loc { loc := buffer.Loc{X: 0, Y: svloc.Line} if w.bufWidth <= 0 { return loc } wordwrap := w.Buf.Settings["wordwrap"].(bool) tabsize := util.IntOpt(w.Buf.Settings["tabsize"]) line := w.Buf.LineBytes(svloc.Line) vloc := VLoc{SLoc: SLoc{svloc.Line, 0}, VisualX: 0} totalwidth := 0 var widths []int if wordwrap { widths = make([]int, 0, w.bufWidth) } else { widths = make([]int, 0, 1) } wordwidth := 0 for len(line) > 0 { r, _, size := util.DecodeCharacter(line) line = line[size:] width := 0 switch r { case '\t': ts := tabsize - (totalwidth % tabsize) width = util.Min(ts, w.bufWidth-vloc.VisualX) totalwidth += ts default: width = runewidth.RuneWidth(r) totalwidth += width } widths = append(widths, width) wordwidth += width // Collect a complete word to know its width. // If wordwrap is off, every single character is a complete "word". if wordwrap { if !util.IsWhitespace(r) && len(line) > 0 && wordwidth < w.bufWidth { continue } } // If a word (or just a wide rune) does not fit in the window if vloc.VisualX+wordwidth > w.bufWidth && vloc.VisualX > 0 { if vloc.Row == svloc.Row { if wordwrap { // it's a word, not a wide rune loc.X-- } return loc } vloc.Row++ vloc.VisualX = 0 } for i := range widths { vloc.VisualX += widths[i] if vloc.Row == svloc.Row && vloc.VisualX > svloc.VisualX { return loc } loc.X++ } widths = widths[:0] wordwidth = 0 if vloc.VisualX >= w.bufWidth { vloc.Row++ vloc.VisualX = 0 } } return loc } func (w *BufWindow) getRowCount(line int) int { eol := buffer.Loc{X: util.CharacterCount(w.Buf.LineBytes(line)), Y: line} return w.getVLocFromLoc(eol).Row + 1 } func (w *BufWindow) scrollUp(s SLoc, n int) SLoc { for n > 0 { if n <= s.Row { s.Row -= n n = 0 } else if s.Line > 0 { s.Line-- n -= s.Row + 1 s.Row = w.getRowCount(s.Line) - 1 } else { s.Row = 0 break } } return s } func (w *BufWindow) scrollDown(s SLoc, n int) SLoc { for n > 0 { rc := w.getRowCount(s.Line) if n < rc-s.Row { s.Row += n n = 0 } else if s.Line < w.Buf.LinesNum()-1 { s.Line++ n -= rc - s.Row s.Row = 0 } else { s.Row = rc - 1 break } } return s } func (w *BufWindow) scroll(s SLoc, n int) SLoc { if n < 0 { return w.scrollUp(s, -n) } return w.scrollDown(s, n) } func (w *BufWindow) diff(s1, s2 SLoc) int { n := 0 for s1.LessThan(s2) { if s1.Line < s2.Line { n += w.getRowCount(s1.Line) - s1.Row s1.Line++ s1.Row = 0 } else { n += s2.Row - s1.Row s1.Row = s2.Row } } return n } // Scroll returns the location which is n visual lines below the location s // i.e. the result of scrolling n lines down. n can be negative, // which means scrolling up. The returned location is guaranteed to be // within the buffer boundaries. func (w *BufWindow) Scroll(s SLoc, n int) SLoc { if !w.Buf.Settings["softwrap"].(bool) { s.Line = util.Clamp(s.Line+n, 0, w.Buf.LinesNum()-1) return s } return w.scroll(s, n) } // Diff returns the difference (the vertical distance) between two SLocs. func (w *BufWindow) Diff(s1, s2 SLoc) int { if !w.Buf.Settings["softwrap"].(bool) { return s2.Line - s1.Line } if s1.GreaterThan(s2) { return -w.diff(s2, s1) } return w.diff(s1, s2) } // SLocFromLoc takes a position in the buffer and returns the location // of the visual line containing this position. func (w *BufWindow) SLocFromLoc(loc buffer.Loc) SLoc { if !w.Buf.Settings["softwrap"].(bool) { return SLoc{loc.Y, 0} } return w.getVLocFromLoc(loc).SLoc } // VLocFromLoc takes a position in the buffer and returns the corresponding // visual location in the linewrapped buffer. func (w *BufWindow) VLocFromLoc(loc buffer.Loc) VLoc { if !w.Buf.Settings["softwrap"].(bool) { tabsize := util.IntOpt(w.Buf.Settings["tabsize"]) visualx := util.StringWidth(w.Buf.LineBytes(loc.Y), loc.X, tabsize) return VLoc{SLoc{loc.Y, 0}, visualx} } return w.getVLocFromLoc(loc) } // LocFromVLoc takes a visual location in the linewrapped buffer and returns // the position in the buffer corresponding to this visual location. func (w *BufWindow) LocFromVLoc(vloc VLoc) buffer.Loc { if !w.Buf.Settings["softwrap"].(bool) { tabsize := util.IntOpt(w.Buf.Settings["tabsize"]) x := util.GetCharPosInLine(w.Buf.LineBytes(vloc.Line), vloc.VisualX, tabsize) return buffer.Loc{x, vloc.Line} } return w.getLocFromVLoc(vloc) } zyedidia-micro-6a62575/internal/display/infowindow.go0000664000175000017510000001513115125206537022237 0ustar nileshnileshpackage display import ( runewidth "github.com/mattn/go-runewidth" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/info" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) type InfoWindow struct { *info.InfoBuf *View hscroll int } func (i *InfoWindow) errStyle() tcell.Style { errStyle := config.DefStyle. Foreground(tcell.ColorBlack). Background(tcell.ColorMaroon) if _, ok := config.Colorscheme["error-message"]; ok { errStyle = config.Colorscheme["error-message"] } return errStyle } func (i *InfoWindow) defStyle() tcell.Style { defStyle := config.DefStyle if _, ok := config.Colorscheme["message"]; ok { defStyle = config.Colorscheme["message"] } return defStyle } func NewInfoWindow(b *info.InfoBuf) *InfoWindow { iw := new(InfoWindow) iw.InfoBuf = b iw.View = new(View) iw.Width, iw.Y = screen.Screen.Size() iw.Y-- return iw } func (i *InfoWindow) Resize(w, h int) { i.Width = w i.Y = h } func (i *InfoWindow) SetBuffer(b *buffer.Buffer) { i.InfoBuf.Buffer = b } func (i *InfoWindow) Relocate() bool { return false } func (i *InfoWindow) GetView() *View { return i.View } func (i *InfoWindow) SetView(v *View) {} func (i *InfoWindow) SetActive(b bool) {} func (i *InfoWindow) IsActive() bool { return true } func (i *InfoWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc { c := i.Buffer.GetActiveCursor() l := i.Buffer.LineBytes(0) n := util.CharacterCountInString(i.Msg) return buffer.Loc{c.GetCharPosInLine(l, vloc.X-n), 0} } func (i *InfoWindow) BufView() View { return View{ X: 0, Y: i.Y, Width: i.Width, Height: 1, StartLine: SLoc{0, 0}, StartCol: 0, } } func (i *InfoWindow) Scroll(s SLoc, n int) SLoc { return s } func (i *InfoWindow) Diff(s1, s2 SLoc) int { return 0 } func (i *InfoWindow) SLocFromLoc(loc buffer.Loc) SLoc { return SLoc{0, 0} } func (i *InfoWindow) VLocFromLoc(loc buffer.Loc) VLoc { return VLoc{SLoc{0, 0}, loc.X} } func (i *InfoWindow) LocFromVLoc(vloc VLoc) buffer.Loc { return buffer.Loc{vloc.VisualX, 0} } func (i *InfoWindow) Clear() { for x := 0; x < i.Width; x++ { screen.SetContent(x, i.Y, ' ', nil, i.defStyle()) } } func (i *InfoWindow) displayBuffer() { b := i.Buffer line := b.LineBytes(0) activeC := b.GetActiveCursor() blocX := 0 vlocX := util.CharacterCountInString(i.Msg) tabsize := 4 line, nColsBeforeStart, bslice := util.SliceVisualEnd(line, blocX, tabsize) blocX = bslice draw := func(r rune, combc []rune, style tcell.Style) { if nColsBeforeStart <= 0 { bloc := buffer.Loc{X: blocX, Y: 0} if activeC.HasSelection() && (bloc.GreaterEqual(activeC.CurSelection[0]) && bloc.LessThan(activeC.CurSelection[1]) || bloc.LessThan(activeC.CurSelection[0]) && bloc.GreaterEqual(activeC.CurSelection[1])) { // The current character is selected style = i.defStyle().Reverse(true) if s, ok := config.Colorscheme["selection"]; ok { style = s } } screen.SetContent(vlocX, i.Y, r, combc, style) vlocX += runewidth.RuneWidth(r) } nColsBeforeStart-- } totalwidth := blocX - nColsBeforeStart for len(line) > 0 { curVX := vlocX curBX := blocX r, combc, size := util.DecodeCharacter(line) width := 0 switch r { case '\t': width = tabsize - (totalwidth % tabsize) for j := 0; j < width; j++ { draw(' ', nil, i.defStyle()) } default: width = runewidth.RuneWidth(r) draw(r, combc, i.defStyle()) } blocX++ line = line[size:] if activeC.X == curBX { screen.ShowCursor(curVX, i.Y) } totalwidth += width if vlocX >= i.Width { break } } if activeC.X == blocX { screen.ShowCursor(vlocX, i.Y) } } var keydisplay = []string{"^Q Quit, ^S Save, ^O Open, ^G Help, ^E Command Bar, ^K Cut Line", "^F Find, ^Z Undo, ^Y Redo, ^A Select All, ^D Duplicate Line, ^T New Tab"} func (i *InfoWindow) displayKeyMenu() { // TODO: maybe make this based on the actual keybindings for y := 0; y < len(keydisplay); y++ { for x := 0; x < i.Width; x++ { if x < len(keydisplay[y]) { screen.SetContent(x, i.Y-len(keydisplay)+y, rune(keydisplay[y][x]), nil, i.defStyle()) } else { screen.SetContent(x, i.Y-len(keydisplay)+y, ' ', nil, i.defStyle()) } } } } func (i *InfoWindow) totalSize() int { sum := 0 for _, n := range i.Suggestions { sum += runewidth.StringWidth(n) + 1 } return sum } func (i *InfoWindow) scrollToSuggestion() { x := 0 s := i.totalSize() for j, n := range i.Suggestions { c := util.CharacterCountInString(n) if j == i.CurSuggestion { if x+c >= i.hscroll+i.Width { i.hscroll = util.Clamp(x+c+1-i.Width, 0, s-i.Width) } else if x < i.hscroll { i.hscroll = util.Clamp(x-1, 0, s-i.Width) } break } x += c + 1 } if s-i.Width <= 0 { i.hscroll = 0 } } func (i *InfoWindow) Display() { if i.HasPrompt || config.GlobalSettings["infobar"].(bool) { i.Clear() x := 0 if config.GetGlobalOption("keymenu").(bool) { i.displayKeyMenu() } if !i.HasPrompt && !i.HasMessage && !i.HasError { return } i.Clear() style := i.defStyle() if i.HasError { style = i.errStyle() } display := i.Msg for _, c := range display { screen.SetContent(x, i.Y, c, nil, style) x += runewidth.RuneWidth(c) } if i.HasPrompt { i.displayBuffer() } } if i.HasSuggestions && len(i.Suggestions) > 1 { i.scrollToSuggestion() x := -i.hscroll done := false statusLineStyle := config.DefStyle.Reverse(true) if style, ok := config.Colorscheme["statusline.suggestions"]; ok { statusLineStyle = style } else if style, ok := config.Colorscheme["statusline"]; ok { statusLineStyle = style } keymenuOffset := 0 if config.GetGlobalOption("keymenu").(bool) { keymenuOffset = len(keydisplay) } draw := func(r rune, s tcell.Style) { y := i.Y - keymenuOffset - 1 rw := runewidth.RuneWidth(r) for j := 0; j < rw; j++ { c := r if j > 0 { c = ' ' } if x == i.Width-1 && !done { screen.SetContent(i.Width-1, y, '>', nil, s) x++ break } else if x == 0 && i.hscroll > 0 { screen.SetContent(0, y, '<', nil, s) } else if x >= 0 && x < i.Width { screen.SetContent(x, y, c, nil, s) } x++ } } for j, s := range i.Suggestions { style := statusLineStyle if i.CurSuggestion == j { style = style.Reverse(true) } for _, r := range s { draw(r, style) // screen.SetContent(x, i.Y-keymenuOffset-1, r, nil, style) } draw(' ', statusLineStyle) } for x < i.Width { draw(' ', statusLineStyle) } } } zyedidia-micro-6a62575/internal/display/bufwindow.go0000664000175000017510000005432315125206537022066 0ustar nileshnileshpackage display import ( "strconv" "strings" runewidth "github.com/mattn/go-runewidth" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) // The BufWindow provides a way of displaying a certain section of a buffer. type BufWindow struct { *View // Buffer being shown in this window Buf *buffer.Buffer active bool sline *StatusLine bufWidth int bufHeight int gutterOffset int hasMessage bool maxLineNumLength int drawDivider bool } // NewBufWindow creates a new window at a location in the screen with a width and height func NewBufWindow(x, y, width, height int, buf *buffer.Buffer) *BufWindow { w := new(BufWindow) w.View = new(View) w.X, w.Y, w.Width, w.Height = x, y, width, height w.SetBuffer(buf) w.active = true w.sline = NewStatusLine(w) return w } // SetBuffer sets this window's buffer. func (w *BufWindow) SetBuffer(b *buffer.Buffer) { w.Buf = b b.OptionCallback = func(option string, nativeValue any) { if option == "softwrap" { if nativeValue.(bool) { w.StartCol = 0 } else { w.StartLine.Row = 0 } } if option == "softwrap" || option == "wordwrap" { w.Relocate() for _, c := range w.Buf.GetCursors() { c.LastWrappedVisualX = c.GetVisualX(true) } } if option == "diffgutter" || option == "ruler" || option == "scrollbar" || option == "statusline" { w.updateDisplayInfo() w.Relocate() } } b.GetVisualX = func(loc buffer.Loc) int { return w.VLocFromLoc(loc).VisualX } } // GetView gets the view. func (w *BufWindow) GetView() *View { return w.View } // GetView sets the view. func (w *BufWindow) SetView(view *View) { w.View = view } // Resize resizes this window. func (w *BufWindow) Resize(width, height int) { w.Width, w.Height = width, height w.updateDisplayInfo() w.Relocate() } // SetActive marks the window as active. func (w *BufWindow) SetActive(b bool) { w.active = b } // IsActive returns true if this window is active. func (w *BufWindow) IsActive() bool { return w.active } // BufView returns the width, height and x,y location of the actual buffer. // It is not exactly the same as the whole window which also contains gutter, // ruler, scrollbar and statusline. func (w *BufWindow) BufView() View { return View{ X: w.X + w.gutterOffset, Y: w.Y, Width: w.bufWidth, Height: w.bufHeight, StartLine: w.StartLine, StartCol: w.StartCol, } } func (w *BufWindow) updateDisplayInfo() { b := w.Buf w.drawDivider = false if !b.Settings["statusline"].(bool) { _, h := screen.Screen.Size() infoY := h if config.GetGlobalOption("infobar").(bool) { infoY-- } if w.Y+w.Height != infoY { w.drawDivider = true } } w.bufHeight = w.Height if b.Settings["statusline"].(bool) || w.drawDivider { w.bufHeight-- } scrollbarWidth := 0 if w.Buf.Settings["scrollbar"].(bool) && w.Buf.LinesNum() > w.Height && w.Width > 0 { scrollbarWidth = 1 } w.hasMessage = len(b.Messages) > 0 // We need to know the string length of the largest line number // so we can pad appropriately when displaying line numbers w.maxLineNumLength = len(strconv.Itoa(b.LinesNum())) w.gutterOffset = 0 if w.hasMessage { w.gutterOffset += 2 } if b.Settings["diffgutter"].(bool) { w.gutterOffset++ } if b.Settings["ruler"].(bool) { w.gutterOffset += w.maxLineNumLength + 1 } if w.gutterOffset > w.Width-scrollbarWidth { w.gutterOffset = w.Width - scrollbarWidth } prevBufWidth := w.bufWidth w.bufWidth = w.Width - w.gutterOffset - scrollbarWidth if w.bufWidth != prevBufWidth && w.Buf.Settings["softwrap"].(bool) { for _, c := range w.Buf.GetCursors() { c.LastWrappedVisualX = c.GetVisualX(true) } } } func (w *BufWindow) getStartInfo(n, lineN int) ([]byte, int, int, *tcell.Style) { tabsize := util.IntOpt(w.Buf.Settings["tabsize"]) width := 0 bloc := buffer.Loc{0, lineN} b := w.Buf.LineBytes(lineN) curStyle := config.DefStyle var s *tcell.Style for len(b) > 0 { r, _, size := util.DecodeCharacter(b) curStyle, found := w.getStyle(curStyle, bloc) if found { s = &curStyle } w := 0 switch r { case '\t': ts := tabsize - (width % tabsize) w = ts default: w = runewidth.RuneWidth(r) } if width+w > n { return b, n - width, bloc.X, s } width += w b = b[size:] bloc.X++ } return b, n - width, bloc.X, s } // Clear resets all cells in this window to the default style func (w *BufWindow) Clear() { for y := 0; y < w.Height; y++ { for x := 0; x < w.Width; x++ { screen.SetContent(w.X+x, w.Y+y, ' ', nil, config.DefStyle) } } } // Relocate moves the view window so that the cursor is in view // This is useful if the user has scrolled far away, and then starts typing // Returns true if the window location is moved func (w *BufWindow) Relocate() bool { b := w.Buf height := w.bufHeight ret := false activeC := w.Buf.GetActiveCursor() scrollmargin := int(b.Settings["scrollmargin"].(float64)) c := w.SLocFromLoc(activeC.Loc) bStart := SLoc{0, 0} bEnd := w.SLocFromLoc(b.End()) if c.LessThan(w.Scroll(w.StartLine, scrollmargin)) && c.GreaterThan(w.Scroll(bStart, scrollmargin-1)) { w.StartLine = w.Scroll(c, -scrollmargin) ret = true } else if c.LessThan(w.StartLine) { w.StartLine = c ret = true } if c.GreaterThan(w.Scroll(w.StartLine, height-1-scrollmargin)) && c.LessEqual(w.Scroll(bEnd, -scrollmargin)) { w.StartLine = w.Scroll(c, -height+1+scrollmargin) ret = true } else if c.GreaterThan(w.Scroll(bEnd, -scrollmargin)) && c.GreaterThan(w.Scroll(w.StartLine, height-1)) { w.StartLine = w.Scroll(bEnd, -height+1) ret = true } // horizontal relocation (scrolling) if !b.Settings["softwrap"].(bool) { cx := activeC.GetVisualX(false) rw := runewidth.RuneWidth(activeC.RuneUnder(activeC.X)) if rw == 0 { rw = 1 // tab or newline } if cx < w.StartCol { w.StartCol = cx ret = true } if cx+rw > w.StartCol+w.bufWidth { w.StartCol = cx - w.bufWidth + rw ret = true } } return ret } // LocFromVisual takes a visual location (x and y position) and returns the // position in the buffer corresponding to the visual location // If the requested position does not correspond to a buffer location it returns // the nearest position func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc { vx := svloc.X - w.X - w.gutterOffset if vx < 0 { vx = 0 } vloc := VLoc{ SLoc: w.Scroll(w.StartLine, svloc.Y-w.Y), VisualX: vx + w.StartCol, } return w.LocFromVLoc(vloc) } func (w *BufWindow) drawGutter(vloc *buffer.Loc, bloc *buffer.Loc) { char := ' ' s := config.DefStyle for _, m := range w.Buf.Messages { if m.Start.Y == bloc.Y || m.End.Y == bloc.Y { s = m.Style() char = '>' break } } for i := 0; i < 2 && vloc.X < w.gutterOffset; i++ { screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, char, nil, s) vloc.X++ } } func (w *BufWindow) drawDiffGutter(backgroundStyle tcell.Style, softwrapped bool, vloc *buffer.Loc, bloc *buffer.Loc) { if vloc.X >= w.gutterOffset { return } symbol := ' ' styleName := "" switch w.Buf.DiffStatus(bloc.Y) { case buffer.DSAdded: symbol = '\u258C' // Left half block styleName = "diff-added" case buffer.DSModified: symbol = '\u258C' // Left half block styleName = "diff-modified" case buffer.DSDeletedAbove: if !softwrapped { symbol = '\u2594' // Upper one eighth block styleName = "diff-deleted" } } style := backgroundStyle if s, ok := config.Colorscheme[styleName]; ok { foreground, _, _ := s.Decompose() style = style.Foreground(foreground) } screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, symbol, nil, style) vloc.X++ } func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, vloc *buffer.Loc, bloc *buffer.Loc) { cursorLine := w.Buf.GetActiveCursor().Loc.Y var lineInt int if w.Buf.Settings["relativeruler"] == false || cursorLine == bloc.Y { lineInt = bloc.Y + 1 } else { lineInt = bloc.Y - cursorLine } lineNum := []rune(strconv.Itoa(util.Abs(lineInt))) // Write the spaces before the line number if necessary for i := 0; i < w.maxLineNumLength-len(lineNum) && vloc.X < w.gutterOffset; i++ { screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle) vloc.X++ } // Write the actual line number for i := 0; i < len(lineNum) && vloc.X < w.gutterOffset; i++ { if softwrapped || (w.bufWidth == 0 && w.Buf.Settings["softwrap"] == true) { screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle) } else { screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, lineNum[i], nil, lineNumStyle) } vloc.X++ } // Write the extra space if vloc.X < w.gutterOffset { screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle) vloc.X++ } } // getStyle returns the highlight style for the given character position // If there is no change to the current highlight style it just returns that func (w *BufWindow) getStyle(style tcell.Style, bloc buffer.Loc) (tcell.Style, bool) { if group, ok := w.Buf.Match(bloc.Y)[bloc.X]; ok { s := config.GetColor(group.String()) return s, true } return style, false } func (w *BufWindow) showCursor(x, y int, main bool) { if w.active { if main { screen.ShowCursor(x, y) } else { screen.ShowFakeCursorMulti(x, y) } } } // displayBuffer draws the buffer being shown in this window on the screen.Screen func (w *BufWindow) displayBuffer() { b := w.Buf if w.Height <= 0 || w.Width <= 0 { return } maxWidth := w.gutterOffset + w.bufWidth if b.ModifiedThisFrame { if b.Settings["diffgutter"].(bool) { b.UpdateDiff() } b.ModifiedThisFrame = false } var matchingBraces []buffer.Loc // bracePairs is defined in buffer.go if b.Settings["matchbrace"].(bool) { for _, c := range b.GetCursors() { if c.HasSelection() { continue } mb, left, found := b.FindMatchingBrace(c.Loc) if found { matchingBraces = append(matchingBraces, mb) if !left { if b.Settings["matchbracestyle"].(string) != "highlight" { matchingBraces = append(matchingBraces, c.Loc) } } else { matchingBraces = append(matchingBraces, c.Loc.Move(-1, b)) } } } } lineNumStyle := config.DefStyle if style, ok := config.Colorscheme["line-number"]; ok { lineNumStyle = style } curNumStyle := config.DefStyle if style, ok := config.Colorscheme["current-line-number"]; ok { if !b.Settings["cursorline"].(bool) { curNumStyle = lineNumStyle } else { curNumStyle = style } } softwrap := b.Settings["softwrap"].(bool) wordwrap := softwrap && b.Settings["wordwrap"].(bool) tabsize := util.IntOpt(b.Settings["tabsize"]) colorcolumn := util.IntOpt(b.Settings["colorcolumn"]) // this represents the current draw position // within the current window vloc := buffer.Loc{X: 0, Y: 0} if softwrap { // the start line may be partially out of the current window vloc.Y = -w.StartLine.Row } // this represents the current draw position in the buffer (char positions) bloc := buffer.Loc{X: -1, Y: w.StartLine.Line} cursors := b.GetCursors() curStyle := config.DefStyle // Parse showchars which is in the format of key1=val1,key2=val2,... spacechars := " " tabchars := b.Settings["indentchar"].(string) var indentspacechars string var indenttabchars string for _, entry := range strings.Split(b.Settings["showchars"].(string), ",") { split := strings.SplitN(entry, "=", 2) if len(split) < 2 { continue } key, val := split[0], split[1] switch key { case "space": spacechars = val case "tab": tabchars = val case "ispace": indentspacechars = val case "itab": indenttabchars = val } } for ; vloc.Y < w.bufHeight; vloc.Y++ { vloc.X = 0 currentLine := false for _, c := range cursors { if !c.HasSelection() && bloc.Y == c.Y && w.active { currentLine = true break } } s := lineNumStyle if currentLine { s = curNumStyle } if vloc.Y >= 0 { if w.hasMessage { w.drawGutter(&vloc, &bloc) } if b.Settings["diffgutter"].(bool) { w.drawDiffGutter(s, false, &vloc, &bloc) } if b.Settings["ruler"].(bool) { w.drawLineNum(s, false, &vloc, &bloc) } } else { vloc.X = w.gutterOffset } bline := b.LineBytes(bloc.Y) blineLen := util.CharacterCount(bline) leadingwsEnd := len(util.GetLeadingWhitespace(bline)) trailingwsStart := blineLen - util.CharacterCount(util.GetTrailingWhitespace(bline)) line, nColsBeforeStart, bslice, startStyle := w.getStartInfo(w.StartCol, bloc.Y) if startStyle != nil { curStyle = *startStyle } bloc.X = bslice // returns the rune to be drawn, style of it and if the bg should be preserved getRuneStyle := func(r rune, style tcell.Style, showoffset int, linex int, isplaceholder bool) (rune, tcell.Style, bool) { if nColsBeforeStart > 0 || vloc.Y < 0 || isplaceholder { return r, style, false } for _, mb := range matchingBraces { if mb.X == bloc.X && mb.Y == bloc.Y { if b.Settings["matchbracestyle"].(string) == "highlight" { if s, ok := config.Colorscheme["match-brace"]; ok { return r, s, false } else { return r, style.Reverse(true), false } } else { return r, style.Underline(true), false } } } if r != '\t' && r != ' ' { return r, style, false } var indentrunes []rune switch r { case '\t': if bloc.X < leadingwsEnd && indenttabchars != "" { indentrunes = []rune(indenttabchars) } else { indentrunes = []rune(tabchars) } case ' ': if linex%tabsize == 0 && bloc.X < leadingwsEnd && indentspacechars != "" { indentrunes = []rune(indentspacechars) } else { indentrunes = []rune(spacechars) } } var drawrune rune if showoffset < len(indentrunes) { drawrune = indentrunes[showoffset] } else { // use space if no showchars or after we showed showchars drawrune = ' ' } if s, ok := config.Colorscheme["indent-char"]; ok { fg, _, _ := s.Decompose() style = style.Foreground(fg) } preservebg := false if b.Settings["hltaberrors"].(bool) && bloc.X < leadingwsEnd { if s, ok := config.Colorscheme["tab-error"]; ok { if b.Settings["tabstospaces"].(bool) && r == '\t' { fg, _, _ := s.Decompose() style = style.Background(fg) preservebg = true } else if !b.Settings["tabstospaces"].(bool) && r == ' ' { fg, _, _ := s.Decompose() style = style.Background(fg) preservebg = true } } } if b.Settings["hltrailingws"].(bool) { if s, ok := config.Colorscheme["trailingws"]; ok { if bloc.X >= trailingwsStart && bloc.X < blineLen { hl := true for _, c := range cursors { if c.NewTrailingWsY == bloc.Y { hl = false break } } if hl { fg, _, _ := s.Decompose() style = style.Background(fg) preservebg = true } } } } return drawrune, style, preservebg } draw := func(r rune, combc []rune, style tcell.Style, highlight bool, showcursor bool, preservebg bool) { defer func() { if nColsBeforeStart <= 0 { vloc.X++ } nColsBeforeStart-- }() if nColsBeforeStart > 0 || vloc.Y < 0 { return } if highlight { if w.Buf.HighlightSearch && w.Buf.SearchMatch(bloc) { style = config.DefStyle.Reverse(true) if s, ok := config.Colorscheme["hlsearch"]; ok { style = s } } _, origBg, _ := style.Decompose() _, defBg, _ := config.DefStyle.Decompose() // syntax or hlsearch highlighting with non-default background takes precedence // over cursor-line and color-column if !preservebg && origBg != defBg { preservebg = true } for _, c := range cursors { if c.HasSelection() && (bloc.GreaterEqual(c.CurSelection[0]) && bloc.LessThan(c.CurSelection[1]) || bloc.LessThan(c.CurSelection[0]) && bloc.GreaterEqual(c.CurSelection[1])) { // The current character is selected style = config.DefStyle.Reverse(true) if s, ok := config.Colorscheme["selection"]; ok { style = s } } if b.Settings["cursorline"].(bool) && w.active && !preservebg && !c.HasSelection() && c.Y == bloc.Y { if s, ok := config.Colorscheme["cursor-line"]; ok { fg, _, _ := s.Decompose() style = style.Background(fg) } } } for _, m := range b.Messages { if bloc.GreaterEqual(m.Start) && bloc.LessThan(m.End) || bloc.LessThan(m.End) && bloc.GreaterEqual(m.Start) { style = style.Underline(true) break } } if s, ok := config.Colorscheme["color-column"]; ok { if colorcolumn != 0 && vloc.X-w.gutterOffset+w.StartCol == colorcolumn && !preservebg { fg, _, _ := s.Decompose() style = style.Background(fg) } } } screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, combc, style) if showcursor { for _, c := range cursors { if c.X == bloc.X && c.Y == bloc.Y && !c.HasSelection() { w.showCursor(w.X+vloc.X, w.Y+vloc.Y, c.Num == 0) } } } } wrap := func() { vloc.X = 0 if vloc.Y >= 0 { if w.hasMessage { w.drawGutter(&vloc, &bloc) } if b.Settings["diffgutter"].(bool) { w.drawDiffGutter(lineNumStyle, true, &vloc, &bloc) } // This will draw an empty line number because the current line is wrapped if b.Settings["ruler"].(bool) { w.drawLineNum(lineNumStyle, true, &vloc, &bloc) } } else { vloc.X = w.gutterOffset } } type glyph struct { r rune combc []rune style tcell.Style width int } var word []glyph if wordwrap { word = make([]glyph, 0, w.bufWidth) } else { word = make([]glyph, 0, 1) } wordwidth := 0 totalwidth := w.StartCol - nColsBeforeStart for len(line) > 0 && vloc.X < maxWidth { r, combc, size := util.DecodeCharacter(line) line = line[size:] loc := buffer.Loc{X: bloc.X + len(word), Y: bloc.Y} curStyle, _ = w.getStyle(curStyle, loc) width := 0 linex := totalwidth switch r { case '\t': ts := tabsize - (totalwidth % tabsize) width = util.Min(ts, maxWidth-vloc.X) totalwidth += ts default: width = runewidth.RuneWidth(r) totalwidth += width } word = append(word, glyph{r, combc, curStyle, width}) wordwidth += width // Collect a complete word to know its width. // If wordwrap is off, every single character is a complete "word". if wordwrap { if !util.IsWhitespace(r) && len(line) > 0 && wordwidth < w.bufWidth { continue } } // If a word (or just a wide rune) does not fit in the window if vloc.X+wordwidth > maxWidth && vloc.X > w.gutterOffset { for vloc.X < maxWidth { draw(' ', nil, config.DefStyle, false, false, true) } // We either stop or we wrap to draw the word in the next line if !softwrap { break } else { vloc.Y++ if vloc.Y >= w.bufHeight { break } wrap() } } for _, r := range word { drawrune, drawstyle, preservebg := getRuneStyle(r.r, r.style, 0, linex, false) draw(drawrune, r.combc, drawstyle, true, true, preservebg) // Draw extra characters for tabs or wide runes for i := 1; i < r.width; i++ { if r.r == '\t' { drawrune, drawstyle, preservebg = getRuneStyle('\t', r.style, i, linex+i, false) } else { drawrune, drawstyle, preservebg = getRuneStyle(' ', r.style, i, linex+i, true) } draw(drawrune, nil, drawstyle, true, false, preservebg) } bloc.X++ } word = word[:0] wordwidth = 0 // If we reach the end of the window then we either stop or we wrap for softwrap if vloc.X >= maxWidth { if !softwrap { break } else { vloc.Y++ if vloc.Y >= w.bufHeight { break } wrap() } } } style := config.DefStyle for _, c := range cursors { if b.Settings["cursorline"].(bool) && w.active && !c.HasSelection() && c.Y == bloc.Y { if s, ok := config.Colorscheme["cursor-line"]; ok { fg, _, _ := s.Decompose() style = style.Background(fg) } } } for i := vloc.X; i < maxWidth; i++ { curStyle := style if s, ok := config.Colorscheme["color-column"]; ok { if colorcolumn != 0 && i-w.gutterOffset+w.StartCol == colorcolumn { fg, _, _ := s.Decompose() curStyle = style.Background(fg) } } screen.SetContent(i+w.X, vloc.Y+w.Y, ' ', nil, curStyle) } if vloc.X != maxWidth { // Display newline within a selection drawrune, drawstyle, preservebg := getRuneStyle(' ', config.DefStyle, 0, totalwidth, true) draw(drawrune, nil, drawstyle, true, true, preservebg) } bloc.X = w.StartCol bloc.Y++ if bloc.Y >= b.LinesNum() { break } } } func (w *BufWindow) displayStatusLine() { if w.Buf.Settings["statusline"].(bool) { w.sline.Display() } else if w.drawDivider { divchars := config.GetGlobalOption("divchars").(string) if util.CharacterCountInString(divchars) != 2 { divchars = "|-" } _, _, size := util.DecodeCharacterInString(divchars) divchar, combc, _ := util.DecodeCharacterInString(divchars[size:]) dividerStyle := config.DefStyle if style, ok := config.Colorscheme["divider"]; ok { dividerStyle = style } divreverse := config.GetGlobalOption("divreverse").(bool) if divreverse { dividerStyle = dividerStyle.Reverse(true) } for x := w.X; x < w.X+w.Width; x++ { screen.SetContent(x, w.Y+w.Height-1, divchar, combc, dividerStyle) } } } func (w *BufWindow) displayScrollBar() { if w.Buf.Settings["scrollbar"].(bool) && w.Buf.LinesNum() > w.Height { scrollX := w.X + w.Width - 1 barsize := int(float64(w.Height) / float64(w.Buf.LinesNum()) * float64(w.Height)) if barsize < 1 { barsize = 1 } barstart := w.Y + int(float64(w.StartLine.Line)/float64(w.Buf.LinesNum())*float64(w.Height)) scrollBarStyle := config.DefStyle.Reverse(true) if style, ok := config.Colorscheme["scrollbar"]; ok { scrollBarStyle = style } scrollBarChar := config.GetGlobalOption("scrollbarchar").(string) if util.CharacterCountInString(scrollBarChar) != 1 { scrollBarChar = "|" } scrollBarRune := []rune(scrollBarChar) for y := barstart; y < util.Min(barstart+barsize, w.Y+w.bufHeight); y++ { screen.SetContent(scrollX, y, scrollBarRune[0], nil, scrollBarStyle) } } } // Display displays the buffer and the statusline func (w *BufWindow) Display() { w.updateDisplayInfo() w.displayStatusLine() w.displayScrollBar() w.displayBuffer() } zyedidia-micro-6a62575/internal/config/0000775000175000017510000000000015125206537017324 5ustar nileshnileshzyedidia-micro-6a62575/internal/config/settings.go0000664000175000017510000003627715125206537021532 0ustar nileshnileshpackage config import ( "encoding/json" "errors" "fmt" "os" "path/filepath" "reflect" "runtime" "strconv" "strings" "github.com/micro-editor/json5" "github.com/zyedidia/glob" "github.com/zyedidia/micro/v2/internal/util" "golang.org/x/text/encoding/htmlindex" ) type optionValidator func(string, any) error // a list of settings that need option validators var optionValidators = map[string]optionValidator{ "autosave": validateNonNegativeValue, "clipboard": validateChoice, "colorcolumn": validateNonNegativeValue, "colorscheme": validateColorscheme, "detectlimit": validateNonNegativeValue, "encoding": validateEncoding, "fileformat": validateChoice, "helpsplit": validateChoice, "matchbracestyle": validateChoice, "multiopen": validateChoice, "pageoverlap": validateNonNegativeValue, "reload": validateChoice, "scrollmargin": validateNonNegativeValue, "scrollspeed": validateNonNegativeValue, "tabsize": validatePositiveValue, "truecolor": validateChoice, } // a list of settings with pre-defined choices var OptionChoices = map[string][]string{ "clipboard": {"internal", "external", "terminal"}, "fileformat": {"unix", "dos"}, "helpsplit": {"hsplit", "vsplit"}, "matchbracestyle": {"underline", "highlight"}, "multiopen": {"tab", "hsplit", "vsplit"}, "reload": {"prompt", "auto", "disabled"}, "truecolor": {"auto", "on", "off"}, } // a list of settings that can be globally and locally modified and their // default values var defaultCommonSettings = map[string]any{ "autoindent": true, "autosu": false, "backup": true, "backupdir": "", "basename": false, "colorcolumn": float64(0), "cursorline": true, "detectlimit": float64(100), "diffgutter": false, "encoding": "utf-8", "eofnewline": true, "fastdirty": false, "fileformat": defaultFileFormat(), "filetype": "unknown", "hlsearch": false, "hltaberrors": false, "hltrailingws": false, "ignorecase": true, "incsearch": true, "indentchar": " ", // Deprecated "keepautoindent": false, "matchbrace": true, "matchbraceleft": true, "matchbracestyle": "underline", "mkparents": false, "pageoverlap": float64(2), "permbackup": false, "readonly": false, "relativeruler": false, "reload": "prompt", "rmtrailingws": false, "ruler": true, "savecursor": false, "saveundo": false, "scrollbar": false, "scrollmargin": float64(3), "scrollspeed": float64(2), "showchars": "", "smartpaste": true, "softwrap": false, "splitbottom": true, "splitright": true, "statusformatl": "$(filename) $(modified)$(overwrite)($(line),$(col)) $(status.paste)| ft:$(opt:filetype) | $(opt:fileformat) | $(opt:encoding)", "statusformatr": "$(bind:ToggleKeyMenu): bindings, $(bind:ToggleHelp): help", "statusline": true, "syntax": true, "tabmovement": false, "tabsize": float64(4), "tabstospaces": false, "truecolor": "auto", "useprimary": true, "wordwrap": false, } // a list of settings that should only be globally modified and their // default values var DefaultGlobalOnlySettings = map[string]any{ "autosave": float64(0), "clipboard": "external", "colorscheme": "default", "divchars": "|-", "divreverse": true, "fakecursor": false, "helpsplit": "hsplit", "infobar": true, "keymenu": false, "lockbindings": false, "mouse": true, "multiopen": "tab", "parsecursor": false, "paste": false, "pluginchannels": []string{"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"}, "pluginrepos": []string{}, "savehistory": true, "scrollbarchar": "|", "sucmd": "sudo", "tabhighlight": false, "tabreverse": true, "xterm": false, } // a list of settings that should never be globally modified var LocalSettings = []string{ "filetype", "readonly", } var ( ErrInvalidOption = errors.New("Invalid option") ErrInvalidValue = errors.New("Invalid value") ErrOptNotToggleable = errors.New("Option not toggleable") // The options that the user can set GlobalSettings map[string]any // This is the raw parsed json parsedSettings map[string]any settingsParseError bool // ModifiedSettings is a map of settings which should be written to disk // because they have been modified by the user in this session ModifiedSettings map[string]bool // VolatileSettings is a map of settings which should not be written to disk // because they have been temporarily set for this session only VolatileSettings map[string]bool ) func writeFile(name string, txt []byte) error { return util.SafeWrite(name, txt, false) } func init() { ModifiedSettings = make(map[string]bool) VolatileSettings = make(map[string]bool) } func validateParsedSettings() error { var err error defaults := DefaultAllSettings() for k, v := range parsedSettings { if strings.HasPrefix(reflect.TypeOf(v).String(), "map") { if strings.HasPrefix(k, "ft:") { for k1, v1 := range v.(map[string]any) { if _, ok := defaults[k1]; ok { if e := verifySetting(k1, v1, defaults[k1]); e != nil { err = e parsedSettings[k].(map[string]any)[k1] = defaults[k1] continue } } } } else { if _, e := glob.Compile(k); e != nil { err = errors.New("Error with glob setting " + k + ": " + e.Error()) delete(parsedSettings, k) continue } for k1, v1 := range v.(map[string]any) { if _, ok := defaults[k1]; ok { if e := verifySetting(k1, v1, defaults[k1]); e != nil { err = e parsedSettings[k].(map[string]any)[k1] = defaults[k1] continue } } } } continue } if k == "autosave" { // if autosave is a boolean convert it to float s, ok := v.(bool) if ok { if s { parsedSettings["autosave"] = 8.0 } else { parsedSettings["autosave"] = 0.0 } } continue } if _, ok := defaults[k]; ok { if e := verifySetting(k, v, defaults[k]); e != nil { err = e parsedSettings[k] = defaults[k] continue } } } return err } func ReadSettings() error { parsedSettings = make(map[string]any) filename := filepath.Join(ConfigDir, "settings.json") if _, e := os.Stat(filename); e == nil { input, err := os.ReadFile(filename) if err != nil { settingsParseError = true return errors.New("Error reading settings.json file: " + err.Error()) } if !strings.HasPrefix(string(input), "null") { // Unmarshal the input into the parsed map err = json5.Unmarshal(input, &parsedSettings) if err != nil { settingsParseError = true return errors.New("Error reading settings.json: " + err.Error()) } err = validateParsedSettings() if err != nil { return err } } } return nil } func ParsedSettings() map[string]any { s := make(map[string]any) for k, v := range parsedSettings { s[k] = v } return s } func verifySetting(option string, value any, def any) error { var interfaceArr []any valType := reflect.TypeOf(value) defType := reflect.TypeOf(def) assignable := false switch option { case "pluginrepos", "pluginchannels": assignable = valType.AssignableTo(reflect.TypeOf(interfaceArr)) default: assignable = defType.AssignableTo(valType) } if !assignable { return fmt.Errorf("Error: setting '%s' has incorrect type (%s), using default value: %v (%s)", option, valType, def, defType) } if option == "colorscheme" { // Plugins are not initialized yet, so do not verify if the colorscheme // exists yet, since the colorscheme may be added by a plugin later. return nil } if err := OptionIsValid(option, value); err != nil { return err } return nil } // InitGlobalSettings initializes the options map and sets all options to their default values // Must be called after ReadSettings func InitGlobalSettings() error { var err error GlobalSettings = DefaultAllSettings() for k, v := range parsedSettings { if !strings.HasPrefix(reflect.TypeOf(v).String(), "map") { GlobalSettings[k] = v } } return err } // UpdatePathGlobLocals scans the already parsed settings and sets the options locally // based on whether the path matches a glob // Must be called after ReadSettings func UpdatePathGlobLocals(settings map[string]any, path string) { for k, v := range parsedSettings { if strings.HasPrefix(reflect.TypeOf(v).String(), "map") && !strings.HasPrefix(k, "ft:") { g, _ := glob.Compile(k) if g.MatchString(path) { for k1, v1 := range v.(map[string]any) { settings[k1] = v1 } } } } } // UpdateFileTypeLocals scans the already parsed settings and sets the options locally // based on whether the filetype matches to "ft:" // Must be called after ReadSettings func UpdateFileTypeLocals(settings map[string]any, filetype string) { for k, v := range parsedSettings { if strings.HasPrefix(reflect.TypeOf(v).String(), "map") && strings.HasPrefix(k, "ft:") { if filetype == k[3:] { for k1, v1 := range v.(map[string]any) { if k1 != "filetype" { settings[k1] = v1 } } } } } } // WriteSettings writes the settings to the specified filename as JSON func WriteSettings(filename string) error { if settingsParseError { // Don't write settings if there was a parse error // because this will delete the settings.json if it // is invalid. Instead we should allow the user to fix // it manually. return nil } var err error if _, e := os.Stat(ConfigDir); e == nil { defaults := DefaultAllSettings() // remove any options froms parsedSettings that have since been marked as default for k, v := range parsedSettings { if !strings.HasPrefix(reflect.TypeOf(v).String(), "map") { cur, okcur := GlobalSettings[k] _, vol := VolatileSettings[k] if def, ok := defaults[k]; ok && okcur && !vol && reflect.DeepEqual(cur, def) { delete(parsedSettings, k) } } } // add any options to parsedSettings that have since been marked as non-default for k, v := range GlobalSettings { if def, ok := defaults[k]; !ok || !reflect.DeepEqual(v, def) { if _, wr := ModifiedSettings[k]; wr { parsedSettings[k] = v } } } txt, _ := json.MarshalIndent(parsedSettings, "", " ") txt = append(txt, '\n') err = writeFile(filename, txt) } return err } // OverwriteSettings writes the current settings to settings.json and // resets any user configuration of local settings present in settings.json func OverwriteSettings(filename string) error { settings := make(map[string]any) var err error if _, e := os.Stat(ConfigDir); e == nil { defaults := DefaultAllSettings() for k, v := range GlobalSettings { if def, ok := defaults[k]; !ok || !reflect.DeepEqual(v, def) { if _, wr := ModifiedSettings[k]; wr { settings[k] = v } } } txt, _ := json.MarshalIndent(parsedSettings, "", " ") txt = append(txt, '\n') err = writeFile(filename, txt) } return err } // RegisterCommonOptionPlug creates a new option (called pl.name). This is meant to be called by plugins to add options. func RegisterCommonOptionPlug(pl string, name string, defaultvalue any) error { return RegisterCommonOption(pl+"."+name, defaultvalue) } // RegisterGlobalOptionPlug creates a new global-only option (named pl.name) func RegisterGlobalOptionPlug(pl string, name string, defaultvalue any) error { return RegisterGlobalOption(pl+"."+name, defaultvalue) } // RegisterCommonOption creates a new option func RegisterCommonOption(name string, defaultvalue any) error { if _, ok := GlobalSettings[name]; !ok { GlobalSettings[name] = defaultvalue } defaultCommonSettings[name] = defaultvalue return nil } // RegisterGlobalOption creates a new global-only option func RegisterGlobalOption(name string, defaultvalue any) error { if _, ok := GlobalSettings[name]; !ok { GlobalSettings[name] = defaultvalue } DefaultGlobalOnlySettings[name] = defaultvalue return nil } // GetGlobalOption returns the global value of the given option func GetGlobalOption(name string) any { return GlobalSettings[name] } func defaultFileFormat() string { if runtime.GOOS == "windows" { return "dos" } return "unix" } func GetInfoBarOffset() int { offset := 0 if GetGlobalOption("infobar").(bool) { offset++ } if GetGlobalOption("keymenu").(bool) { offset += 2 } return offset } // DefaultCommonSettings returns a map of all common buffer settings // and their default values func DefaultCommonSettings() map[string]any { commonsettings := make(map[string]any) for k, v := range defaultCommonSettings { commonsettings[k] = v } return commonsettings } // DefaultAllSettings returns a map of all common buffer & global-only settings // and their default values func DefaultAllSettings() map[string]any { allsettings := make(map[string]any) for k, v := range defaultCommonSettings { allsettings[k] = v } for k, v := range DefaultGlobalOnlySettings { allsettings[k] = v } return allsettings } // GetNativeValue parses and validates a value for a given option func GetNativeValue(option, value string) (any, error) { curVal := GetGlobalOption(option) if curVal == nil { return nil, ErrInvalidOption } switch kind := reflect.TypeOf(curVal).Kind(); kind { case reflect.Bool: b, err := util.ParseBool(value) if err != nil { return nil, ErrInvalidValue } return b, nil case reflect.String: return value, nil case reflect.Float64: f, err := strconv.ParseFloat(value, 64) if err != nil { return nil, ErrInvalidValue } return f, nil default: return nil, ErrInvalidValue } } // OptionIsValid checks if a value is valid for a certain option func OptionIsValid(option string, value any) error { if validator, ok := optionValidators[option]; ok { return validator(option, value) } return nil } // Option validators func validatePositiveValue(option string, value any) error { nativeValue, ok := value.(float64) if !ok { return errors.New("Expected numeric type for " + option) } if nativeValue < 1 { return errors.New(option + " must be greater than 0") } return nil } func validateNonNegativeValue(option string, value any) error { nativeValue, ok := value.(float64) if !ok { return errors.New("Expected numeric type for " + option) } if nativeValue < 0 { return errors.New(option + " must be non-negative") } return nil } func validateChoice(option string, value any) error { if choices, ok := OptionChoices[option]; ok { val, ok := value.(string) if !ok { return errors.New("Expected string type for " + option) } for _, v := range choices { if val == v { return nil } } choicesStr := strings.Join(choices, ", ") return errors.New(option + " must be one of: " + choicesStr) } return errors.New("Option has no pre-defined choices") } func validateColorscheme(option string, value any) error { colorscheme, ok := value.(string) if !ok { return errors.New("Expected string type for colorscheme") } if !ColorschemeExists(colorscheme) { return errors.New(colorscheme + " is not a valid colorscheme") } return nil } func validateEncoding(option string, value any) error { _, err := htmlindex.Get(value.(string)) return err } zyedidia-micro-6a62575/internal/config/rtfiles_test.go0000664000175000017510000000172515125206537022367 0ustar nileshnileshpackage config import ( "testing" "github.com/stretchr/testify/assert" ) func init() { InitRuntimeFiles(false) } func TestAddFile(t *testing.T) { AddRuntimeFile(RTPlugin, memoryFile{"foo.lua", []byte("hello world\n")}) AddRuntimeFile(RTSyntax, memoryFile{"bar", []byte("some syntax file\n")}) f1 := FindRuntimeFile(RTPlugin, "foo.lua") assert.NotNil(t, f1) assert.Equal(t, "foo.lua", f1.Name()) data, err := f1.Data() assert.Nil(t, err) assert.Equal(t, []byte("hello world\n"), data) f2 := FindRuntimeFile(RTSyntax, "bar") assert.NotNil(t, f2) assert.Equal(t, "bar", f2.Name()) data, err = f2.Data() assert.Nil(t, err) assert.Equal(t, []byte("some syntax file\n"), data) } func TestFindFile(t *testing.T) { f := FindRuntimeFile(RTSyntax, "go") assert.NotNil(t, f) assert.Equal(t, "go", f.Name()) data, err := f.Data() assert.Nil(t, err) assert.Equal(t, []byte("filetype: go"), data[:12]) e := FindRuntimeFile(RTSyntax, "foobar") assert.Nil(t, e) } zyedidia-micro-6a62575/internal/config/rtfiles.go0000664000175000017510000002144215125206537021326 0ustar nileshnileshpackage config import ( "errors" "log" "os" "path/filepath" "regexp" "strings" rt "github.com/zyedidia/micro/v2/runtime" ) const ( RTColorscheme = 0 RTSyntax = 1 RTHelp = 2 RTPlugin = 3 RTSyntaxHeader = 4 ) var ( NumTypes = 5 // How many filetypes are there ) type RTFiletype int // RuntimeFile allows the program to read runtime data like colorschemes or syntax files type RuntimeFile interface { // Name returns a name of the file without paths or extensions Name() string // Data returns the content of the file. Data() ([]byte, error) } // allFiles contains all available files, mapped by filetype var allFiles [][]RuntimeFile var realFiles [][]RuntimeFile func init() { initRuntimeVars() } func initRuntimeVars() { allFiles = make([][]RuntimeFile, NumTypes) realFiles = make([][]RuntimeFile, NumTypes) } // NewRTFiletype creates a new RTFiletype func NewRTFiletype() int { NumTypes++ allFiles = append(allFiles, []RuntimeFile{}) realFiles = append(realFiles, []RuntimeFile{}) return NumTypes - 1 } // some file on filesystem type realFile string // some asset file type assetFile string // a file with the data stored in memory type memoryFile struct { name string data []byte } func (mf memoryFile) Name() string { return mf.name } func (mf memoryFile) Data() ([]byte, error) { return mf.data, nil } func (rf realFile) Name() string { fn := filepath.Base(string(rf)) return fn[:len(fn)-len(filepath.Ext(fn))] } func (rf realFile) Data() ([]byte, error) { return os.ReadFile(string(rf)) } func (af assetFile) Name() string { fn := filepath.Base(string(af)) return fn[:len(fn)-len(filepath.Ext(fn))] } func (af assetFile) Data() ([]byte, error) { return rt.Asset(string(af)) } // AddRuntimeFile registers a file for the given filetype func AddRuntimeFile(fileType RTFiletype, file RuntimeFile) { allFiles[fileType] = append(allFiles[fileType], file) } // AddRealRuntimeFile registers a file for the given filetype func AddRealRuntimeFile(fileType RTFiletype, file RuntimeFile) { allFiles[fileType] = append(allFiles[fileType], file) realFiles[fileType] = append(realFiles[fileType], file) } // AddRuntimeFilesFromDirectory registers each file from the given directory for // the filetype which matches the file-pattern func AddRuntimeFilesFromDirectory(fileType RTFiletype, directory, pattern string) { files, _ := os.ReadDir(directory) for _, f := range files { if ok, _ := filepath.Match(pattern, f.Name()); !f.IsDir() && ok { fullPath := filepath.Join(directory, f.Name()) AddRealRuntimeFile(fileType, realFile(fullPath)) } } } // AddRuntimeFilesFromAssets registers each file from the given asset-directory for // the filetype which matches the file-pattern func AddRuntimeFilesFromAssets(fileType RTFiletype, directory, pattern string) { files, err := rt.AssetDir(directory) if err != nil { return } assetLoop: for _, f := range files { if ok, _ := filepath.Match(pattern, f); ok { af := assetFile(filepath.Join(directory, f)) for _, rf := range realFiles[fileType] { if af.Name() == rf.Name() { continue assetLoop } } AddRuntimeFile(fileType, af) } } } // FindRuntimeFile finds a runtime file of the given filetype and name // will return nil if no file was found func FindRuntimeFile(fileType RTFiletype, name string) RuntimeFile { for _, f := range ListRuntimeFiles(fileType) { if f.Name() == name { return f } } return nil } // ListRuntimeFiles lists all known runtime files for the given filetype func ListRuntimeFiles(fileType RTFiletype) []RuntimeFile { return allFiles[fileType] } // ListRealRuntimeFiles lists all real runtime files (on disk) for a filetype // these runtime files will be ones defined by the user and loaded from the config directory func ListRealRuntimeFiles(fileType RTFiletype) []RuntimeFile { return realFiles[fileType] } // InitRuntimeFiles initializes all assets files and the config directory. // If `user` is false, InitRuntimeFiles ignores the config directory and // initializes asset files only. func InitRuntimeFiles(user bool) { add := func(fileType RTFiletype, dir, pattern string) { if user { AddRuntimeFilesFromDirectory(fileType, filepath.Join(ConfigDir, dir), pattern) } AddRuntimeFilesFromAssets(fileType, filepath.Join("runtime", dir), pattern) } initRuntimeVars() add(RTColorscheme, "colorschemes", "*.micro") add(RTSyntax, "syntax", "*.yaml") add(RTSyntaxHeader, "syntax", "*.hdr") add(RTHelp, "help", "*.md") } // InitPlugins initializes the plugins func InitPlugins() { Plugins = Plugins[:0] initlua := filepath.Join(ConfigDir, "init.lua") if _, err := os.Stat(initlua); !os.IsNotExist(err) { p := new(Plugin) p.Name = "initlua" p.DirName = "initlua" p.Srcs = append(p.Srcs, realFile(initlua)) p.Builtin = false Plugins = append(Plugins, p) } // Search ConfigDir for plugin-scripts plugdir := filepath.Join(ConfigDir, "plug") files, _ := os.ReadDir(plugdir) isID := regexp.MustCompile(`^[_A-Za-z0-9]+$`).MatchString for _, d := range files { plugpath := filepath.Join(plugdir, d.Name()) if stat, err := os.Stat(plugpath); err == nil && stat.IsDir() { srcs, _ := os.ReadDir(plugpath) p := new(Plugin) p.Name = d.Name() p.DirName = d.Name() for _, f := range srcs { if strings.HasSuffix(f.Name(), ".lua") { p.Srcs = append(p.Srcs, realFile(filepath.Join(plugdir, d.Name(), f.Name()))) } else if strings.HasSuffix(f.Name(), ".json") { data, err := os.ReadFile(filepath.Join(plugdir, d.Name(), f.Name())) if err != nil { continue } p.Info, err = NewPluginInfo(data) if err != nil { continue } p.Name = p.Info.Name } } if !isID(p.Name) || len(p.Srcs) <= 0 { log.Println(p.Name, "is not a plugin") continue } Plugins = append(Plugins, p) } } plugdir = filepath.Join("runtime", "plugins") if files, err := rt.AssetDir(plugdir); err == nil { outer: for _, d := range files { for _, p := range Plugins { if p.Name == d { log.Println(p.Name, "built-in plugin overridden by user-defined one") continue outer } } if srcs, err := rt.AssetDir(filepath.Join(plugdir, d)); err == nil { p := new(Plugin) p.Name = d p.DirName = d p.Builtin = true for _, f := range srcs { if strings.HasSuffix(f, ".lua") { p.Srcs = append(p.Srcs, assetFile(filepath.Join(plugdir, d, f))) } else if strings.HasSuffix(f, ".json") { data, err := rt.Asset(filepath.Join(plugdir, d, f)) if err != nil { continue } p.Info, err = NewPluginInfo(data) if err != nil { continue } p.Name = p.Info.Name } } if !isID(p.Name) || len(p.Srcs) <= 0 { log.Println(p.Name, "is not a plugin") continue } Plugins = append(Plugins, p) } } } } // PluginReadRuntimeFile allows plugin scripts to read the content of a runtime file func PluginReadRuntimeFile(fileType RTFiletype, name string) string { if file := FindRuntimeFile(fileType, name); file != nil { if data, err := file.Data(); err == nil { return string(data) } } return "" } // PluginListRuntimeFiles allows plugins to lists all runtime files of the given type func PluginListRuntimeFiles(fileType RTFiletype) []string { files := ListRuntimeFiles(fileType) result := make([]string, len(files)) for i, f := range files { result[i] = f.Name() } return result } // PluginAddRuntimeFile adds a file to the runtime files for a plugin func PluginAddRuntimeFile(plugin string, filetype RTFiletype, filePath string) error { pl := FindPlugin(plugin) if pl == nil { return errors.New("Plugin " + plugin + " does not exist") } pldir := pl.DirName fullpath := filepath.Join(ConfigDir, "plug", pldir, filePath) if _, err := os.Stat(fullpath); err == nil { AddRealRuntimeFile(filetype, realFile(fullpath)) } else { fullpath = filepath.Join("runtime", "plugins", pldir, filePath) AddRuntimeFile(filetype, assetFile(fullpath)) } return nil } // PluginAddRuntimeFilesFromDirectory adds files from a directory to the runtime files for a plugin func PluginAddRuntimeFilesFromDirectory(plugin string, filetype RTFiletype, directory, pattern string) error { pl := FindPlugin(plugin) if pl == nil { return errors.New("Plugin " + plugin + " does not exist") } pldir := pl.DirName fullpath := filepath.Join(ConfigDir, "plug", pldir, directory) if _, err := os.Stat(fullpath); err == nil { AddRuntimeFilesFromDirectory(filetype, fullpath, pattern) } else { fullpath = filepath.Join("runtime", "plugins", pldir, directory) AddRuntimeFilesFromAssets(filetype, fullpath, pattern) } return nil } // PluginAddRuntimeFileFromMemory adds a file to the runtime files for a plugin from a given string func PluginAddRuntimeFileFromMemory(filetype RTFiletype, filename, data string) { AddRealRuntimeFile(filetype, memoryFile{filename, []byte(data)}) } zyedidia-micro-6a62575/internal/config/plugin_manager.go0000664000175000017510000000255715125206537022654 0ustar nileshnileshpackage config import ( "bytes" "encoding/json" "errors" ) var ( ErrMissingName = errors.New("Missing or empty name field") ErrMissingDesc = errors.New("Missing or empty description field") ErrMissingSite = errors.New("Missing or empty website field") ) // PluginInfo contains all the needed info about a plugin // The info is just strings and are not used beyond that (except // the Site and Install fields should be valid URLs). This means // that the requirements for example can be formatted however the // plugin maker decides, the fields will only be parsed by humans // Name: name of plugin // Desc: description of plugin // Site: home website of plugin // Install: install link for plugin (can be link to repo or zip file) // Vstr: version // Require: list of dependencies and requirements type PluginInfo struct { Name string `json:"Name"` Desc string `json:"Description"` Site string `json:"Website"` } // NewPluginInfo parses a JSON input into a valid PluginInfo struct // Returns an error if there are any missing fields or any invalid fields // There are no optional fields in a plugin info json file func NewPluginInfo(data []byte) (*PluginInfo, error) { var info []PluginInfo dec := json.NewDecoder(bytes.NewReader(data)) // dec.DisallowUnknownFields() // Force errors if err := dec.Decode(&info); err != nil { return nil, err } return &info[0], nil } zyedidia-micro-6a62575/internal/config/plugin_installer_test.go0000664000175000017510000000241715125206537024271 0ustar nileshnileshpackage config import ( "testing" "github.com/blang/semver" "github.com/micro-editor/json5" ) func TestDependencyResolving(t *testing.T) { js := ` [{ "Name": "Foo", "Versions": [{ "Version": "1.0.0" }, { "Version": "1.5.0" },{ "Version": "2.0.0" }] }, { "Name": "Bar", "Versions": [{ "Version": "1.0.0", "Require": {"Foo": ">1.0.0 <2.0.0"} }] }, { "Name": "Unresolvable", "Versions": [{ "Version": "1.0.0", "Require": {"Foo": "<=1.0.0", "Bar": ">0.0.0"} }] }] ` var all PluginPackages err := json5.Unmarshal([]byte(js), &all) if err != nil { t.Error(err) } selected, err := all.Resolve(PluginVersions{}, PluginDependencies{ &PluginDependency{"Bar", semver.MustParseRange(">=1.0.0")}, }) check := func(name, version string) { v := selected.find(name) expected := semver.MustParse(version) if v == nil { t.Errorf("Failed to resolve %s", name) } else if expected.NE(v.Version) { t.Errorf("%s resolved in wrong version %v", name, v) } } if err != nil { t.Error(err) } else { check("Foo", "1.5.0") check("Bar", "1.0.0") } selected, err = all.Resolve(PluginVersions{}, PluginDependencies{ &PluginDependency{"Unresolvable", semver.MustParseRange(">0.0.0")}, }) if err == nil { t.Error("Unresolvable package resolved:", selected) } } zyedidia-micro-6a62575/internal/config/plugin_installer.go0000664000175000017510000004406215125206537023234 0ustar nileshnileshpackage config import ( "archive/zip" "bytes" "fmt" "io" "net/http" "os" "path/filepath" "sort" "strings" "sync" "github.com/blang/semver" "github.com/micro-editor/json5" lua "github.com/yuin/gopher-lua" ulua "github.com/zyedidia/micro/v2/internal/lua" "github.com/zyedidia/micro/v2/internal/util" ) var ( allPluginPackages PluginPackages ) // CorePluginName is a plugin dependency name for the micro core. const CorePluginName = "micro" // PluginChannel contains an url to a json list of PluginRepository type PluginChannel string // PluginChannels is a slice of PluginChannel type PluginChannels []PluginChannel // PluginRepository contains an url to json file containing PluginPackages type PluginRepository string // PluginPackage contains the meta-data of a plugin and all available versions type PluginPackage struct { Name string Description string Author string Tags []string Versions PluginVersions Builtin bool } // PluginPackages is a list of PluginPackage instances. type PluginPackages []*PluginPackage // PluginVersion descripes a version of a PluginPackage. Containing a version, download url and also dependencies. type PluginVersion struct { pack *PluginPackage Version semver.Version Url string Require PluginDependencies } func (pv *PluginVersion) Pack() *PluginPackage { return pv.pack } // PluginVersions is a slice of PluginVersion type PluginVersions []*PluginVersion // PluginDependency descripes a dependency to another plugin or micro itself. type PluginDependency struct { Name string Range semver.Range } // PluginDependencies is a slice of PluginDependency type PluginDependencies []*PluginDependency func (pp *PluginPackage) String() string { buf := new(bytes.Buffer) buf.WriteString("Plugin: ") buf.WriteString(pp.Name) if pp.Builtin { buf.WriteString(" (built-in)") } buf.WriteRune('\n') if pp.Author != "" { buf.WriteString("Author: ") buf.WriteString(pp.Author) buf.WriteRune('\n') } if pp.Description != "" { buf.WriteRune('\n') buf.WriteString(pp.Description) } return buf.String() } func fetchAllSources(count int, fetcher func(i int) PluginPackages) PluginPackages { wgQuery := new(sync.WaitGroup) wgQuery.Add(count) results := make(chan PluginPackages) wgDone := new(sync.WaitGroup) wgDone.Add(1) var packages PluginPackages for i := 0; i < count; i++ { go func(i int) { results <- fetcher(i) wgQuery.Done() }(i) } go func() { packages = make(PluginPackages, 0) for res := range results { packages = append(packages, res...) } wgDone.Done() }() wgQuery.Wait() close(results) wgDone.Wait() return packages } // Fetch retrieves all available PluginPackages from the given channels func (pc PluginChannels) Fetch(out io.Writer) PluginPackages { return fetchAllSources(len(pc), func(i int) PluginPackages { return pc[i].Fetch(out) }) } // Fetch retrieves all available PluginPackages from the given channel func (pc PluginChannel) Fetch(out io.Writer) PluginPackages { resp, err := http.Get(string(pc)) if err != nil { fmt.Fprintln(out, "Failed to query plugin channel:\n", err) return PluginPackages{} } defer resp.Body.Close() decoder := json5.NewDecoder(resp.Body) var repositories []PluginRepository if err := decoder.Decode(&repositories); err != nil { fmt.Fprintln(out, "Failed to decode channel data:\n", err) return PluginPackages{} } return fetchAllSources(len(repositories), func(i int) PluginPackages { return repositories[i].Fetch(out) }) } // Fetch retrieves all available PluginPackages from the given repository func (pr PluginRepository) Fetch(out io.Writer) PluginPackages { resp, err := http.Get(string(pr)) if err != nil { fmt.Fprintln(out, "Failed to query plugin repository:\n", err) return PluginPackages{} } defer resp.Body.Close() decoder := json5.NewDecoder(resp.Body) var plugins PluginPackages if err := decoder.Decode(&plugins); err != nil { fmt.Fprintln(out, "Failed to decode repository data:\n", err) return PluginPackages{} } if len(plugins) > 0 { return PluginPackages{plugins[0]} } return nil // return plugins } // UnmarshalJSON unmarshals raw json to a PluginVersion func (pv *PluginVersion) UnmarshalJSON(data []byte) error { var values struct { Version semver.Version Url string Require map[string]string } if err := json5.Unmarshal(data, &values); err != nil { return err } pv.Version = values.Version pv.Url = values.Url pv.Require = make(PluginDependencies, 0) for k, v := range values.Require { // don't add the dependency if it's the core and // we have a unknown version number. // in that case just accept that dependency (which equals to not adding it.) if k != CorePluginName || !isUnknownCoreVersion() { if vRange, err := semver.ParseRange(v); err == nil { pv.Require = append(pv.Require, &PluginDependency{k, vRange}) } } } return nil } // UnmarshalJSON unmarshals raw json to a PluginPackage func (pp *PluginPackage) UnmarshalJSON(data []byte) error { var values struct { Name string Description string Author string Tags []string Versions PluginVersions } if err := json5.Unmarshal(data, &values); err != nil { return err } pp.Name = values.Name pp.Description = values.Description pp.Author = values.Author pp.Tags = values.Tags pp.Versions = values.Versions for _, v := range pp.Versions { v.pack = pp } return nil } // GetAllPluginPackages gets all PluginPackages which may be available. func GetAllPluginPackages(out io.Writer) PluginPackages { if allPluginPackages == nil { getOption := func(name string) []string { data := GetGlobalOption(name) if strs, ok := data.([]string); ok { return strs } if ifs, ok := data.([]any); ok { result := make([]string, len(ifs)) for i, urlIf := range ifs { if url, ok := urlIf.(string); ok { result[i] = url } else { return nil } } return result } return nil } channels := PluginChannels{} for _, url := range getOption("pluginchannels") { channels = append(channels, PluginChannel(url)) } repos := []PluginRepository{} for _, url := range getOption("pluginrepos") { repos = append(repos, PluginRepository(url)) } allPluginPackages = fetchAllSources(len(repos)+1, func(i int) PluginPackages { if i == 0 { return channels.Fetch(out) } return repos[i-1].Fetch(out) }) } return allPluginPackages } func (pv PluginVersions) find(ppName string) *PluginVersion { for _, v := range pv { if v.pack.Name == ppName { return v } } return nil } // Len returns the number of pluginversions in this slice func (pv PluginVersions) Len() int { return len(pv) } // Swap two entries of the slice func (pv PluginVersions) Swap(i, j int) { pv[i], pv[j] = pv[j], pv[i] } // Less returns true if the version at position i is greater then the version at position j (used for sorting) func (pv PluginVersions) Less(i, j int) bool { return pv[i].Version.GT(pv[j].Version) } // Match returns true if the package matches a given search text func (pp PluginPackage) Match(text string) bool { text = strings.ToLower(text) for _, t := range pp.Tags { if strings.ToLower(t) == text { return true } } if strings.Contains(strings.ToLower(pp.Name), text) { return true } if strings.Contains(strings.ToLower(pp.Description), text) { return true } return false } // IsInstallable returns true if the package can be installed. func (pp PluginPackage) IsInstallable(out io.Writer) error { _, err := GetAllPluginPackages(out).Resolve(GetInstalledVersions(true), PluginDependencies{ &PluginDependency{ Name: pp.Name, Range: semver.Range(func(v semver.Version) bool { return true }), }}) return err } // SearchPlugin retrieves a list of all PluginPackages which match the given search text and // could be or are already installed func SearchPlugin(out io.Writer, texts []string) (plugins PluginPackages) { plugins = make(PluginPackages, 0) pluginLoop: for _, pp := range GetAllPluginPackages(out) { for _, text := range texts { if !pp.Match(text) { continue pluginLoop } } if err := pp.IsInstallable(out); err == nil { plugins = append(plugins, pp) } } return } func isUnknownCoreVersion() bool { _, err := semver.ParseTolerant(util.Version) return err != nil } func newStaticPluginVersion(name, version string, builtin bool) *PluginVersion { vers, err := semver.ParseTolerant(version) if err != nil { if vers, err = semver.ParseTolerant("0.0.0-" + version); err != nil { vers = semver.MustParse("0.0.0-unknown") } } pl := &PluginPackage{ Name: name, Builtin: builtin, } pv := &PluginVersion{ pack: pl, Version: vers, } pl.Versions = PluginVersions{pv} return pv } // GetInstalledVersions returns a list of all currently installed plugins including an entry for // micro itself. This can be used to resolve dependencies. func GetInstalledVersions(withCore bool) PluginVersions { result := PluginVersions{} if withCore { result = append(result, newStaticPluginVersion(CorePluginName, util.Version, true)) } for _, p := range Plugins { if !p.IsLoaded() { continue } version := GetInstalledPluginVersion(p.Name) if pv := newStaticPluginVersion(p.Name, version, p.Builtin); pv != nil { result = append(result, pv) } } return result } // GetInstalledPluginVersion returns the string of the exported VERSION variable of a loaded plugin func GetInstalledPluginVersion(name string) string { plugin := ulua.L.GetGlobal(name) if plugin != lua.LNil { version := ulua.L.GetField(plugin, "VERSION") if str, ok := version.(lua.LString); ok { return string(str) } } return "" } // DownloadAndInstall downloads and installs the given plugin and version func (pv *PluginVersion) DownloadAndInstall(out io.Writer) error { fmt.Fprintf(out, "Downloading %q (%s) from %q\n", pv.pack.Name, pv.Version, pv.Url) resp, err := http.Get(pv.Url) if err != nil { return err } defer resp.Body.Close() data, err := io.ReadAll(resp.Body) if err != nil { return err } zipbuf := bytes.NewReader(data) z, err := zip.NewReader(zipbuf, zipbuf.Size()) if err != nil { return err } targetDir := filepath.Join(ConfigDir, "plug", pv.pack.Name) dirPerm := os.FileMode(0755) if err = os.MkdirAll(targetDir, dirPerm); err != nil { return err } // Check if all files in zip are in the same directory. // this might be the case if the plugin zip contains the whole plugin dir // instead of its content. var prefix string allPrefixed := false for i, f := range z.File { parts := strings.Split(f.Name, "/") if i == 0 { prefix = parts[0] } else if parts[0] != prefix { allPrefixed = false break } else { // switch to true since we have at least a second file allPrefixed = true } } // Install files and directory's for _, f := range z.File { parts := strings.Split(f.Name, "/") if allPrefixed { parts = parts[1:] } targetName := filepath.Join(targetDir, filepath.Join(parts...)) if f.FileInfo().IsDir() { if err := os.MkdirAll(targetName, dirPerm); err != nil { return err } } else { basepath := filepath.Dir(targetName) if err := os.MkdirAll(basepath, dirPerm); err != nil { return err } content, err := f.Open() if err != nil { return err } defer content.Close() target, err := os.Create(targetName) if err != nil { return err } defer target.Close() if _, err = io.Copy(target, content); err != nil { return err } } } return nil } func (pl PluginPackages) Get(name string) *PluginPackage { for _, p := range pl { if p.Name == name { return p } } return nil } func (pl PluginPackages) GetAllVersions(name string) PluginVersions { result := make(PluginVersions, 0) p := pl.Get(name) if p != nil { result = append(result, p.Versions...) } return result } func (req PluginDependencies) Join(other PluginDependencies) PluginDependencies { m := make(map[string]*PluginDependency) for _, r := range req { m[r.Name] = r } for _, o := range other { cur, ok := m[o.Name] if ok { m[o.Name] = &PluginDependency{ o.Name, o.Range.AND(cur.Range), } } else { m[o.Name] = o } } result := make(PluginDependencies, 0, len(m)) for _, v := range m { result = append(result, v) } return result } // Resolve resolves dependencies between different plugins func (all PluginPackages) Resolve(selectedVersions PluginVersions, open PluginDependencies) (PluginVersions, error) { if len(open) == 0 { return selectedVersions, nil } currentRequirement, stillOpen := open[0], open[1:] if currentRequirement != nil { if selVersion := selectedVersions.find(currentRequirement.Name); selVersion != nil { if currentRequirement.Range(selVersion.Version) { return all.Resolve(selectedVersions, stillOpen) } return nil, fmt.Errorf("unable to find a matching version for \"%s\"", currentRequirement.Name) } availableVersions := all.GetAllVersions(currentRequirement.Name) sort.Sort(availableVersions) for _, version := range availableVersions { if currentRequirement.Range(version.Version) { resolved, err := all.Resolve(append(selectedVersions, version), stillOpen.Join(version.Require)) if err == nil { return resolved, nil } } } return nil, fmt.Errorf("unable to find a matching version for \"%s\"", currentRequirement.Name) } return selectedVersions, nil } func (pv PluginVersions) install(out io.Writer) { anyInstalled := false currentlyInstalled := GetInstalledVersions(true) for _, sel := range pv { if sel.pack.Name != CorePluginName { shouldInstall := true if pv := currentlyInstalled.find(sel.pack.Name); pv != nil { if pv.Version.NE(sel.Version) { fmt.Fprintln(out, "Uninstalling", sel.pack.Name) UninstallPlugin(out, sel.pack.Name) } else { shouldInstall = false } } if shouldInstall { if err := sel.DownloadAndInstall(out); err != nil { fmt.Fprintln(out, err) return } anyInstalled = true } } } if anyInstalled { fmt.Fprintln(out, "One or more plugins installed.") } else { fmt.Fprintln(out, "Nothing to install / update") } } // UninstallPlugin deletes the plugin folder of the given plugin func UninstallPlugin(out io.Writer, name string) { for _, p := range Plugins { if !p.IsLoaded() { continue } if p.Name == name { p.Loaded = false if err := os.RemoveAll(filepath.Join(ConfigDir, "plug", p.DirName)); err != nil { fmt.Fprintln(out, err) return } break } } } // Install installs the plugin func (pl PluginPackage) Install(out io.Writer) { selected, err := GetAllPluginPackages(out).Resolve(GetInstalledVersions(true), PluginDependencies{ &PluginDependency{ Name: pl.Name, Range: semver.Range(func(v semver.Version) bool { return true }), }}) if err != nil { fmt.Fprintln(out, err) return } selected.install(out) } // UpdatePlugins updates the given plugins func UpdatePlugins(out io.Writer, plugins []string) { // if no plugins are specified, update all installed plugins. if len(plugins) == 0 { for _, p := range Plugins { if !p.IsLoaded() || p.Builtin || p.Name == "initlua" { continue } plugins = append(plugins, p.Name) } } fmt.Fprintln(out, "Checking for plugin updates") microVersion := PluginVersions{ newStaticPluginVersion(CorePluginName, util.Version, true), } var updates = make(PluginDependencies, 0) for _, name := range plugins { pv := GetInstalledPluginVersion(name) r, err := semver.ParseRange(">=" + pv) // Try to get newer versions. if err == nil { updates = append(updates, &PluginDependency{ Name: name, Range: r, }) } } selected, err := GetAllPluginPackages(out).Resolve(microVersion, updates) if err != nil { fmt.Fprintln(out, err) return } selected.install(out) } func PluginCommand(out io.Writer, cmd string, args []string) { switch cmd { case "install": installedVersions := GetInstalledVersions(false) for _, plugin := range args { pp := GetAllPluginPackages(out).Get(plugin) if pp == nil { fmt.Fprintln(out, "Unknown plugin \""+plugin+"\"") } else if err := pp.IsInstallable(out); err != nil { fmt.Fprintln(out, "Error installing "+plugin+": ", err) } else { for _, installed := range installedVersions { if pp.Name == installed.Pack().Name { if pp.Versions[0].Version.Compare(installed.Version) == 1 { fmt.Fprintln(out, pp.Name, "is already installed but out-of-date: use 'plugin update "+pp.Name+"' to update") } else { fmt.Fprintln(out, pp.Name, "is already installed") } } } pp.Install(out) } } case "remove": removed := "" for _, plugin := range args { if plugin == "initlua" { fmt.Fprintln(out, "initlua cannot be removed, but can be disabled via settings.") continue } // check if the plugin exists. for _, p := range Plugins { if p.Name == plugin && p.Builtin { fmt.Fprintln(out, p.Name, "is a built-in plugin which cannot be removed, but can be disabled via settings.") continue } if p.Name == plugin { UninstallPlugin(out, plugin) removed += plugin + " " continue } } } removed = strings.TrimSpace(removed) if removed != "" { fmt.Fprintln(out, "Removed", removed) } else { fmt.Fprintln(out, "No plugins removed") } case "update": UpdatePlugins(out, args) case "list": plugins := GetInstalledVersions(false) fmt.Fprintln(out, "The following plugins are currently installed:") for _, p := range plugins { if p.Pack().Name == "initlua" { fmt.Fprintf(out, "%s\n", "initlua") } else if p.Pack().Builtin { fmt.Fprintf(out, "%s (built-in)\n", p.Pack().Name) } else { fmt.Fprintf(out, "%s (%s)\n", p.Pack().Name, p.Version) } } case "search": plugins := SearchPlugin(out, args) fmt.Fprintln(out, len(plugins), "plugins found") for _, p := range plugins { fmt.Fprintln(out, "----------------") fmt.Fprintln(out, p.String()) } fmt.Fprintln(out, "----------------") case "available": packages := GetAllPluginPackages(out) fmt.Fprintln(out, "Available Plugins:") for _, pkg := range packages { fmt.Fprintln(out, pkg.Name) } default: fmt.Fprintln(out, "Invalid plugin command") } } zyedidia-micro-6a62575/internal/config/plugin.go0000664000175000017510000000647615125206537021166 0ustar nileshnileshpackage config import ( "errors" "log" lua "github.com/yuin/gopher-lua" ulua "github.com/zyedidia/micro/v2/internal/lua" ) // ErrNoSuchFunction is returned when Call is executed on a function that does not exist var ErrNoSuchFunction = errors.New("No such function exists") // LoadAllPlugins loads all detected plugins (in runtime/plugins and ConfigDir/plugins) func LoadAllPlugins() error { var reterr error for _, p := range Plugins { err := p.Load() if err != nil { reterr = err } } return reterr } // RunPluginFn runs a given function in all plugins // returns an error if any of the plugins had an error func RunPluginFn(fn string, args ...lua.LValue) error { var reterr error for _, p := range Plugins { if !p.IsLoaded() { continue } _, err := p.Call(fn, args...) if err != nil && err != ErrNoSuchFunction { reterr = errors.New("Plugin " + p.Name + ": " + err.Error()) } } return reterr } // RunPluginFnBool runs a function in all plugins and returns // false if any one of them returned false // also returns an error if any of the plugins had an error func RunPluginFnBool(settings map[string]any, fn string, args ...lua.LValue) (bool, error) { var reterr error retbool := true for _, p := range Plugins { if !p.IsLoaded() || (settings != nil && settings[p.Name] == false) { continue } val, err := p.Call(fn, args...) if err == ErrNoSuchFunction { continue } if err != nil { reterr = errors.New("Plugin " + p.Name + ": " + err.Error()) continue } if v, ok := val.(lua.LBool); ok { retbool = retbool && bool(v) } } return retbool, reterr } // Plugin stores information about the source files/info for a plugin type Plugin struct { DirName string // name of plugin folder Name string // name of plugin Info *PluginInfo // json file containing info Srcs []RuntimeFile // lua files Loaded bool Builtin bool } // IsLoaded returns if a plugin is enabled func (p *Plugin) IsLoaded() bool { if v, ok := GlobalSettings[p.Name]; ok { return v.(bool) && p.Loaded } return true } // Plugins is a list of all detected plugins (enabled or disabled) var Plugins []*Plugin // Load creates an option for the plugin and runs all source files func (p *Plugin) Load() error { if v, ok := GlobalSettings[p.Name]; ok && !v.(bool) { return nil } for _, f := range p.Srcs { dat, err := f.Data() if err != nil { return err } err = ulua.LoadFile(p.Name, f.Name(), dat) if err != nil { return err } } p.Loaded = true RegisterCommonOption(p.Name, true) return nil } // Call calls a given function in this plugin func (p *Plugin) Call(fn string, args ...lua.LValue) (lua.LValue, error) { plug := ulua.L.GetGlobal(p.Name) if plug == lua.LNil { log.Println("Plugin does not exist:", p.Name, "at", p.DirName, ":", p) return nil, nil } luafn := ulua.L.GetField(plug, fn) if luafn == lua.LNil { return nil, ErrNoSuchFunction } err := ulua.L.CallByParam(lua.P{ Fn: luafn, NRet: 1, Protect: true, }, args...) if err != nil { return nil, err } ret := ulua.L.Get(-1) ulua.L.Pop(1) return ret, nil } // FindPlugin returns the plugin with the given name func FindPlugin(name string) *Plugin { var pl *Plugin for _, p := range Plugins { if !p.IsLoaded() { continue } if p.Name == name { pl = p break } } return pl } zyedidia-micro-6a62575/internal/config/globals.go0000664000175000017510000000054115125206537021276 0ustar nileshnileshpackage config const ( DoubleClickThreshold = 400 // How many milliseconds to wait before a second click is not a double click ) var Bindings map[string]map[string]string func init() { Bindings = map[string]map[string]string{ "command": make(map[string]string), "buffer": make(map[string]string), "terminal": make(map[string]string), } } zyedidia-micro-6a62575/internal/config/config.go0000664000175000017510000000263115125206537021122 0ustar nileshnileshpackage config import ( "errors" "os" "path/filepath" homedir "github.com/mitchellh/go-homedir" ) var ConfigDir string // InitConfigDir finds the configuration directory for micro according to the XDG spec. // If no directory is found, it creates one. func InitConfigDir(flagConfigDir string) error { var e error microHome := os.Getenv("MICRO_CONFIG_HOME") if microHome == "" { // The user has not set $MICRO_CONFIG_HOME so we'll try $XDG_CONFIG_HOME xdgHome := os.Getenv("XDG_CONFIG_HOME") if xdgHome == "" { // The user has not set $XDG_CONFIG_HOME so we should act like it was set to ~/.config home, err := homedir.Dir() if err != nil { return errors.New("Error finding your home directory\nCan't load config files: " + err.Error()) } xdgHome = filepath.Join(home, ".config") } microHome = filepath.Join(xdgHome, "micro") } ConfigDir = microHome if len(flagConfigDir) > 0 { if _, err := os.Stat(flagConfigDir); os.IsNotExist(err) { e = errors.New("Error: " + flagConfigDir + " does not exist. Defaulting to " + ConfigDir + ".") } else { ConfigDir = flagConfigDir return nil } } // Create micro config home directory if it does not exist // This creates parent directories and does nothing if it already exists err := os.MkdirAll(ConfigDir, os.ModePerm) if err != nil { return errors.New("Error creating configuration directory: " + err.Error()) } return e } zyedidia-micro-6a62575/internal/config/colorscheme_test.go0000664000175000017510000000356015125206537023221 0ustar nileshnileshpackage config import ( "testing" "github.com/micro-editor/tcell/v2" "github.com/stretchr/testify/assert" ) func TestSimpleStringToStyle(t *testing.T) { s := StringToStyle("lightblue,magenta") fg, bg, _ := s.Decompose() assert.Equal(t, tcell.ColorBlue, fg) assert.Equal(t, tcell.ColorPurple, bg) } func TestAttributeStringToStyle(t *testing.T) { s := StringToStyle("bold cyan,brightcyan") fg, bg, attr := s.Decompose() assert.Equal(t, tcell.ColorTeal, fg) assert.Equal(t, tcell.ColorAqua, bg) assert.NotEqual(t, 0, attr&tcell.AttrBold) } func TestMultiAttributesStringToStyle(t *testing.T) { s := StringToStyle("bold italic underline cyan,brightcyan") fg, bg, attr := s.Decompose() assert.Equal(t, tcell.ColorTeal, fg) assert.Equal(t, tcell.ColorAqua, bg) assert.NotEqual(t, 0, attr&tcell.AttrBold) assert.NotEqual(t, 0, attr&tcell.AttrItalic) assert.NotEqual(t, 0, attr&tcell.AttrUnderline) } func TestColor256StringToStyle(t *testing.T) { s := StringToStyle("128,60") fg, bg, _ := s.Decompose() assert.Equal(t, tcell.Color128, fg) assert.Equal(t, tcell.Color60, bg) } func TestColorHexStringToStyle(t *testing.T) { s := StringToStyle("#deadbe,#ef1234") fg, bg, _ := s.Decompose() assert.Equal(t, tcell.NewRGBColor(222, 173, 190), fg) assert.Equal(t, tcell.NewRGBColor(239, 18, 52), bg) } func TestColorschemeParser(t *testing.T) { testColorscheme := `color-link default "#F8F8F2,#282828" color-link comment "#75715E,#282828" # comment color-link identifier "#66D9EF,#282828" #comment color-link constant "#AE81FF,#282828" color-link constant.string "#E6DB74,#282828" color-link constant.string.char "#BDE6AD,#282828"` c, err := ParseColorscheme("testColorscheme", testColorscheme, nil) assert.Nil(t, err) fg, bg, _ := c["comment"].Decompose() assert.Equal(t, tcell.NewRGBColor(117, 113, 94), fg) assert.Equal(t, tcell.NewRGBColor(40, 40, 40), bg) } zyedidia-micro-6a62575/internal/config/colorscheme.go0000664000175000017510000001610215125206537022156 0ustar nileshnileshpackage config import ( "errors" "regexp" "strconv" "strings" "github.com/micro-editor/tcell/v2" ) // DefStyle is Micro's default style var DefStyle tcell.Style = tcell.StyleDefault // Colorscheme is the current colorscheme var Colorscheme map[string]tcell.Style // GetColor takes in a syntax group and returns the colorscheme's style for that group func GetColor(color string) tcell.Style { st := DefStyle if color == "" { return st } groups := strings.Split(color, ".") if len(groups) > 1 { curGroup := "" for i, g := range groups { if i != 0 { curGroup += "." } curGroup += g if style, ok := Colorscheme[curGroup]; ok { st = style } } } else if style, ok := Colorscheme[color]; ok { st = style } else { st = StringToStyle(color) } return st } // ColorschemeExists checks if a given colorscheme exists func ColorschemeExists(colorschemeName string) bool { return FindRuntimeFile(RTColorscheme, colorschemeName) != nil } // InitColorscheme picks and initializes the colorscheme when micro starts func InitColorscheme() error { Colorscheme = make(map[string]tcell.Style) DefStyle = tcell.StyleDefault c, err := LoadDefaultColorscheme() if err == nil { Colorscheme = c } else { // The colorscheme setting seems broken (maybe because we have not validated // it earlier, see comment in verifySetting()). So reset it to the default // colorscheme and try again. GlobalSettings["colorscheme"] = DefaultGlobalOnlySettings["colorscheme"] if c, err2 := LoadDefaultColorscheme(); err2 == nil { Colorscheme = c } } return err } // LoadDefaultColorscheme loads the default colorscheme from $(ConfigDir)/colorschemes func LoadDefaultColorscheme() (map[string]tcell.Style, error) { var parsedColorschemes []string return LoadColorscheme(GlobalSettings["colorscheme"].(string), &parsedColorschemes) } // LoadColorscheme loads the given colorscheme from a directory func LoadColorscheme(colorschemeName string, parsedColorschemes *[]string) (map[string]tcell.Style, error) { c := make(map[string]tcell.Style) file := FindRuntimeFile(RTColorscheme, colorschemeName) if file == nil { return c, errors.New(colorschemeName + " is not a valid colorscheme") } if data, err := file.Data(); err != nil { return c, errors.New("Error loading colorscheme: " + err.Error()) } else { var err error c, err = ParseColorscheme(file.Name(), string(data), parsedColorschemes) if err != nil { return c, err } } return c, nil } // ParseColorscheme parses the text definition for a colorscheme and returns the corresponding object // Colorschemes are made up of color-link statements linking a color group to a list of colors // For example, color-link keyword (blue,red) makes all keywords have a blue foreground and // red background func ParseColorscheme(name string, text string, parsedColorschemes *[]string) (map[string]tcell.Style, error) { var err error colorParser := regexp.MustCompile(`color-link\s+(\S*)\s+"(.*)"`) includeParser := regexp.MustCompile(`include\s+"(.*)"`) lines := strings.Split(text, "\n") c := make(map[string]tcell.Style) if parsedColorschemes != nil { *parsedColorschemes = append(*parsedColorschemes, name) } lineLoop: for _, line := range lines { if strings.TrimSpace(line) == "" || strings.TrimSpace(line)[0] == '#' { // Ignore this line continue } matches := includeParser.FindSubmatch([]byte(line)) if len(matches) == 2 { // support includes only in case parsedColorschemes are given if parsedColorschemes != nil { include := string(matches[1]) for _, name := range *parsedColorschemes { // check for circular includes... if name == include { // ...and prevent them continue lineLoop } } includeScheme, err := LoadColorscheme(include, parsedColorschemes) if err != nil { return c, err } for k, v := range includeScheme { c[k] = v } } continue } matches = colorParser.FindSubmatch([]byte(line)) if len(matches) == 3 { link := string(matches[1]) colors := string(matches[2]) style := StringToStyle(colors) c[link] = style if link == "default" { DefStyle = style } } else { err = errors.New("Color-link statement is not valid: " + line) } } return c, err } // StringToStyle returns a style from a string // The strings must be in the format "extra foregroundcolor,backgroundcolor" // The 'extra' can be bold, reverse, italic or underline func StringToStyle(str string) tcell.Style { var fg, bg string spaceSplit := strings.Split(str, " ") split := strings.Split(spaceSplit[len(spaceSplit)-1], ",") if len(split) > 1 { fg, bg = split[0], split[1] } else { fg = split[0] } fg = strings.TrimSpace(fg) bg = strings.TrimSpace(bg) var fgColor, bgColor tcell.Color var ok bool if fg == "" || fg == "default" { fgColor, _, _ = DefStyle.Decompose() } else { fgColor, ok = StringToColor(fg) if !ok { fgColor, _, _ = DefStyle.Decompose() } } if bg == "" || bg == "default" { _, bgColor, _ = DefStyle.Decompose() } else { bgColor, ok = StringToColor(bg) if !ok { _, bgColor, _ = DefStyle.Decompose() } } style := DefStyle.Foreground(fgColor).Background(bgColor) if strings.Contains(str, "bold") { style = style.Bold(true) } if strings.Contains(str, "italic") { style = style.Italic(true) } if strings.Contains(str, "reverse") { style = style.Reverse(true) } if strings.Contains(str, "underline") { style = style.Underline(true) } return style } // StringToColor returns a tcell color from a string representation of a color // We accept either bright... or light... to mean the brighter version of a color func StringToColor(str string) (tcell.Color, bool) { switch str { case "black": return tcell.ColorBlack, true case "red": return tcell.ColorMaroon, true case "green": return tcell.ColorGreen, true case "yellow": return tcell.ColorOlive, true case "blue": return tcell.ColorNavy, true case "magenta": return tcell.ColorPurple, true case "cyan": return tcell.ColorTeal, true case "white": return tcell.ColorSilver, true case "brightblack", "lightblack": return tcell.ColorGray, true case "brightred", "lightred": return tcell.ColorRed, true case "brightgreen", "lightgreen": return tcell.ColorLime, true case "brightyellow", "lightyellow": return tcell.ColorYellow, true case "brightblue", "lightblue": return tcell.ColorBlue, true case "brightmagenta", "lightmagenta": return tcell.ColorFuchsia, true case "brightcyan", "lightcyan": return tcell.ColorAqua, true case "brightwhite", "lightwhite": return tcell.ColorWhite, true case "default": return tcell.ColorDefault, true default: // Check if this is a 256 color if num, err := strconv.Atoi(str); err == nil { return GetColor256(num), true } // Check if this is a truecolor hex value if len(str) == 7 && str[0] == '#' { return tcell.GetColor(str), true } return tcell.ColorDefault, false } } // GetColor256 returns the tcell color for a number between 0 and 255 func GetColor256(color int) tcell.Color { if color == 0 { return tcell.ColorDefault } return tcell.PaletteColor(color) } zyedidia-micro-6a62575/internal/config/autosave.go0000664000175000017510000000141315125206537021501 0ustar nileshnileshpackage config import ( "time" ) var Autosave chan bool var autotime chan float64 func init() { Autosave = make(chan bool) autotime = make(chan float64) } func SetAutoTime(a float64) { autotime <- a } func StartAutoSave() { go func() { var a float64 var t *time.Timer var elapsed <-chan time.Time for { select { case a = <-autotime: if t != nil { t.Stop() for len(elapsed) > 0 { <-elapsed } } if a > 0 { if t != nil { t.Reset(time.Duration(a * float64(time.Second))) } else { t = time.NewTimer(time.Duration(a * float64(time.Second))) elapsed = t.C } } case <-elapsed: if a > 0 { t.Reset(time.Duration(a * float64(time.Second))) Autosave <- true } } } }() } zyedidia-micro-6a62575/internal/clipboard/0000775000175000017510000000000015125206537020016 5ustar nileshnileshzyedidia-micro-6a62575/internal/clipboard/terminal.go0000664000175000017510000000125615125206537022164 0ustar nileshnileshpackage clipboard import ( "errors" "time" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/screen" ) type terminalClipboard struct{} var terminal terminalClipboard func (t terminalClipboard) read(reg string) (string, error) { screen.Screen.GetClipboard(reg) // wait at most 200ms for response for { select { case event := <-screen.Events: e, ok := event.(*tcell.EventPaste) if ok { return e.Text(), nil } case <-time.After(200 * time.Millisecond): return "", errors.New("No clipboard received from terminal") } } } func (t terminalClipboard) write(text, reg string) error { return screen.Screen.SetClipboard(text, reg) } zyedidia-micro-6a62575/internal/clipboard/multi.go0000664000175000017510000000244115125206537021500 0ustar nileshnileshpackage clipboard import ( "bytes" ) // For storing multi cursor clipboard contents type multiClipboard map[Register][]string var multi multiClipboard func (c multiClipboard) getAllText(r Register) string { content := c[r] if content == nil { return "" } buf := &bytes.Buffer{} for _, s := range content { buf.WriteString(s) } return buf.String() } func (c multiClipboard) getText(r Register, num int) string { content := c[r] if content == nil || len(content) <= num { return "" } return content[num] } // isValid checks if the text stored in this multi-clipboard is the same as the // text stored in the system clipboard (provided as an argument), and therefore // if it is safe to use the multi-clipboard for pasting instead of the system // clipboard. func (c multiClipboard) isValid(r Register, clipboard string, ncursors int) bool { content := c[r] if content == nil || len(content) != ncursors { return false } return clipboard == c.getAllText(r) } func (c multiClipboard) writeText(text string, r Register, num int, ncursors int) { content := c[r] if content == nil || len(content) != ncursors { content = make([]string, ncursors, ncursors) c[r] = content } if num >= ncursors { return } content[num] = text } func init() { multi = make(multiClipboard) } zyedidia-micro-6a62575/internal/clipboard/internal.go0000664000175000017510000000044415125206537022163 0ustar nileshnileshpackage clipboard type internalClipboard map[Register]string var internal internalClipboard func init() { internal = make(internalClipboard) } func (c internalClipboard) read(r Register) string { return c[r] } func (c internalClipboard) write(text string, r Register) { c[r] = text } zyedidia-micro-6a62575/internal/clipboard/clipboard.go0000664000175000017510000001013515125206537022304 0ustar nileshnileshpackage clipboard import ( "errors" "github.com/zyedidia/clipper" ) type Method int const ( // External relies on external tools for accessing the clipboard // These include xclip, xsel, wl-clipboard for linux, pbcopy/pbpaste on Mac, // and Syscalls on Windows. External Method = iota // Terminal uses the terminal to manage the clipboard via OSC 52. Many // terminals do not support OSC 52, in which case this method won't work. Terminal // Internal just manages the clipboard with an internal buffer and doesn't // attempt to interface with the system clipboard Internal ) // CurrentMethod is the method used to store clipboard information var CurrentMethod Method = Internal // A Register is a buffer used to store text. The system clipboard has the 'clipboard' // and 'primary' (linux-only) registers, but other registers may be used internal to micro. type Register int const ( // ClipboardReg is the main system clipboard ClipboardReg Register = -1 // PrimaryReg is the system primary clipboard (linux only) PrimaryReg = -2 ) var clipboard clipper.Clipboard // Initialize attempts to initialize the clipboard using the given method func Initialize(m Method) error { var err error switch m { case External: clips := make([]clipper.Clipboard, 0, len(clipper.Clipboards)+1) clips = append(clips, &clipper.Custom{ Name: "micro-clip", }) clips = append(clips, clipper.Clipboards...) clipboard, err = clipper.GetClipboard(clips...) } if err != nil { CurrentMethod = Internal } return err } // SetMethod changes the clipboard access method func SetMethod(m string) Method { switch m { case "internal": CurrentMethod = Internal case "external": CurrentMethod = External case "terminal": CurrentMethod = Terminal } return CurrentMethod } // Read reads from a clipboard register func Read(r Register) (string, error) { return read(r, CurrentMethod) } // Write writes text to a clipboard register func Write(text string, r Register) error { return write(text, r, CurrentMethod) } // ReadMulti reads text from a clipboard register for a certain multi-cursor func ReadMulti(r Register, num, ncursors int) (string, error) { clip, err := Read(r) if err != nil { return "", err } if ValidMulti(r, clip, ncursors) { return multi.getText(r, num), nil } return clip, nil } // WriteMulti writes text to a clipboard register for a certain multi-cursor func WriteMulti(text string, r Register, num int, ncursors int) error { return writeMulti(text, r, num, ncursors, CurrentMethod) } // ValidMulti checks if the internal multi-clipboard is valid and up-to-date // with the system clipboard func ValidMulti(r Register, clip string, ncursors int) bool { return multi.isValid(r, clip, ncursors) } func writeMulti(text string, r Register, num int, ncursors int, m Method) error { multi.writeText(text, r, num, ncursors) return write(multi.getAllText(r), r, m) } func read(r Register, m Method) (string, error) { switch m { case External: switch r { case ClipboardReg: b, e := clipboard.ReadAll(clipper.RegClipboard) return string(b), e case PrimaryReg: b, e := clipboard.ReadAll(clipper.RegPrimary) return string(b), e default: return internal.read(r), nil } case Internal: return internal.read(r), nil case Terminal: switch r { case ClipboardReg: // terminal paste works by sending an esc sequence to the // terminal to trigger a paste event return terminal.read("clipboard") case PrimaryReg: return terminal.read("primary") default: return internal.read(r), nil } } return "", errors.New("Invalid clipboard method") } func write(text string, r Register, m Method) error { switch m { case External: switch r { case ClipboardReg: return clipboard.WriteAll(clipper.RegClipboard, []byte(text)) case PrimaryReg: return clipboard.WriteAll(clipper.RegPrimary, []byte(text)) default: internal.write(text, r) } case Internal: internal.write(text, r) case Terminal: switch r { case ClipboardReg: return terminal.write(text, "c") case PrimaryReg: return terminal.write(text, "p") default: internal.write(text, r) } } return nil } zyedidia-micro-6a62575/internal/buffer/0000775000175000017510000000000015125206537017330 5ustar nileshnileshzyedidia-micro-6a62575/internal/buffer/stack_test.go0000664000175000017510000000116215125206537022023 0ustar nileshnileshpackage buffer import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestStack(t *testing.T) { s := new(TEStack) e1 := &TextEvent{ EventType: TextEventReplace, Time: time.Now(), } e2 := &TextEvent{ EventType: TextEventInsert, Time: time.Now(), } s.Push(e1) s.Push(e2) p := s.Peek() assert.Equal(t, p.EventType, TextEventInsert) p = s.Pop() assert.Equal(t, p.EventType, TextEventInsert) p = s.Peek() assert.Equal(t, p.EventType, TextEventReplace) p = s.Pop() assert.Equal(t, p.EventType, TextEventReplace) p = s.Pop() assert.Nil(t, p) p = s.Peek() assert.Nil(t, p) } zyedidia-micro-6a62575/internal/buffer/stack.go0000664000175000017510000000152115125206537020763 0ustar nileshnileshpackage buffer // TEStack is a simple implementation of a LIFO stack for text events type TEStack struct { Top *Element Size int } // An Element which is stored in the Stack type Element struct { Value *TextEvent Next *Element } // Len returns the stack's length func (s *TEStack) Len() int { return s.Size } // Push a new element onto the stack func (s *TEStack) Push(value *TextEvent) { s.Top = &Element{value, s.Top} s.Size++ } // Pop removes the top element from the stack and returns its value // If the stack is empty, return nil func (s *TEStack) Pop() (value *TextEvent) { if s.Size > 0 { value, s.Top = s.Top.Value, s.Top.Next s.Size-- return } return nil } // Peek returns the top element of the stack without removing it func (s *TEStack) Peek() *TextEvent { if s.Size > 0 { return s.Top.Value } return nil } zyedidia-micro-6a62575/internal/buffer/settings.go0000664000175000017510000001045315125206537021522 0ustar nileshnileshpackage buffer import ( "crypto/md5" "reflect" "github.com/zyedidia/micro/v2/internal/config" ulua "github.com/zyedidia/micro/v2/internal/lua" "github.com/zyedidia/micro/v2/internal/screen" "golang.org/x/text/encoding/htmlindex" "golang.org/x/text/encoding/unicode" luar "layeh.com/gopher-luar" ) func (b *Buffer) ReloadSettings(reloadFiletype bool) { settings := config.ParsedSettings() config.UpdatePathGlobLocals(settings, b.AbsPath) oldFiletype := b.Settings["filetype"].(string) _, local := b.LocalSettings["filetype"] _, volatile := config.VolatileSettings["filetype"] if reloadFiletype && !local && !volatile { // need to update filetype before updating other settings based on it b.Settings["filetype"] = "unknown" if v, ok := settings["filetype"]; ok { b.Settings["filetype"] = v } } // update syntax rules, which will also update filetype if needed b.UpdateRules() curFiletype := b.Settings["filetype"].(string) if oldFiletype != curFiletype { b.doCallbacks("filetype", oldFiletype, curFiletype) } config.UpdateFileTypeLocals(settings, curFiletype) for k, v := range config.DefaultCommonSettings() { if k == "filetype" { // prevent recursion continue } if _, ok := config.VolatileSettings[k]; ok { // reload should not override volatile settings continue } if _, ok := b.LocalSettings[k]; ok { // reload should not override local settings continue } if _, ok := settings[k]; ok { b.DoSetOptionNative(k, settings[k]) } else { b.DoSetOptionNative(k, v) } } } func (b *Buffer) DoSetOptionNative(option string, nativeValue any) { oldValue := b.Settings[option] if reflect.DeepEqual(oldValue, nativeValue) { return } b.Settings[option] = nativeValue if option == "fastdirty" { if !nativeValue.(bool) { if b.Size() > LargeFileThreshold { b.Settings["fastdirty"] = true } else { if !b.isModified { b.calcHash(&b.origHash) } else { // prevent using an old stale origHash value b.origHash = [md5.Size]byte{} } } } } else if option == "statusline" { screen.Redraw() } else if option == "filetype" { b.ReloadSettings(false) } else if option == "fileformat" { switch b.Settings["fileformat"].(string) { case "unix": b.Endings = FFUnix case "dos": b.Endings = FFDos } b.setModified() } else if option == "syntax" { if !nativeValue.(bool) { b.ClearMatches() } else { b.UpdateRules() } } else if option == "encoding" { enc, err := htmlindex.Get(b.Settings["encoding"].(string)) if err != nil { enc = unicode.UTF8 b.Settings["encoding"] = "utf-8" } b.encoding = enc b.setModified() } else if option == "readonly" && b.Type.Kind == BTDefault.Kind { b.Type.Readonly = nativeValue.(bool) } else if option == "hlsearch" { for _, buf := range OpenBuffers { if b.SharedBuffer == buf.SharedBuffer { buf.HighlightSearch = nativeValue.(bool) } } } else { for _, pl := range config.Plugins { if option == pl.Name { if nativeValue.(bool) { if !pl.Loaded { pl.Load() } _, err := pl.Call("init") if err != nil && err != config.ErrNoSuchFunction { screen.TermMessage(err) } } else if !nativeValue.(bool) && pl.Loaded { _, err := pl.Call("deinit") if err != nil && err != config.ErrNoSuchFunction { screen.TermMessage(err) } } } } } b.doCallbacks(option, oldValue, nativeValue) } func (b *Buffer) SetOptionNative(option string, nativeValue any) error { if err := config.OptionIsValid(option, nativeValue); err != nil { return err } b.DoSetOptionNative(option, nativeValue) b.LocalSettings[option] = true return nil } // SetOption sets a given option to a value just for this buffer func (b *Buffer) SetOption(option, value string) error { if _, ok := b.Settings[option]; !ok { return config.ErrInvalidOption } nativeValue, err := config.GetNativeValue(option, value) if err != nil { return err } return b.SetOptionNative(option, nativeValue) } func (b *Buffer) doCallbacks(option string, oldValue any, newValue any) { if b.OptionCallback != nil { b.OptionCallback(option, newValue) } if err := config.RunPluginFn("onBufferOptionChanged", luar.New(ulua.L, b), luar.New(ulua.L, option), luar.New(ulua.L, oldValue), luar.New(ulua.L, newValue)); err != nil { screen.TermMessage(err) } } zyedidia-micro-6a62575/internal/buffer/serialize.go0000664000175000017510000000463515125206537021656 0ustar nileshnileshpackage buffer import ( "bytes" "encoding/gob" "errors" "os" "path/filepath" "time" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/util" ) // The SerializedBuffer holds the types that get serialized when a buffer is saved // These are used for the savecursor and saveundo options type SerializedBuffer struct { EventHandler *EventHandler Cursor Loc ModTime time.Time } // Serialize serializes the buffer to config.ConfigDir/buffers func (b *Buffer) Serialize() error { if !b.Settings["savecursor"].(bool) && !b.Settings["saveundo"].(bool) { return nil } if b.Path == "" { return nil } var buf bytes.Buffer err := gob.NewEncoder(&buf).Encode(SerializedBuffer{ b.EventHandler, b.GetActiveCursor().Loc, b.ModTime, }) if err != nil { return err } name, resolveName := util.DetermineEscapePath(filepath.Join(config.ConfigDir, "buffers"), b.AbsPath) err = util.SafeWrite(name, buf.Bytes(), true) if err != nil { return err } if resolveName != "" { err = util.SafeWrite(resolveName, []byte(b.AbsPath), true) if err != nil { return err } } return nil } // Unserialize loads the buffer info from config.ConfigDir/buffers func (b *Buffer) Unserialize() error { // If either savecursor or saveundo is turned on, we need to load the serialized information // from ~/.config/micro/buffers if b.Path == "" { return nil } name, _ := util.DetermineEscapePath(filepath.Join(config.ConfigDir, "buffers"), b.AbsPath) file, err := os.Open(name) if err == nil { defer file.Close() var buffer SerializedBuffer decoder := gob.NewDecoder(file) err = decoder.Decode(&buffer) if err != nil { return errors.New(err.Error() + "\nYou may want to remove the files in ~/.config/micro/buffers (these files\nstore the information for the 'saveundo' and 'savecursor' options) if\nthis problem persists.\nThis may be caused by upgrading to version 2.0, and removing the 'buffers'\ndirectory will reset the cursor and undo history and solve the problem.") } if b.Settings["savecursor"].(bool) { b.StartCursor = buffer.Cursor } if b.Settings["saveundo"].(bool) { // We should only use last time's eventhandler if the file wasn't modified by someone else in the meantime if b.ModTime == buffer.ModTime { b.EventHandler = buffer.EventHandler b.EventHandler.cursors = b.cursors b.EventHandler.buf = b.SharedBuffer } } } return nil } zyedidia-micro-6a62575/internal/buffer/search.go0000664000175000017510000001420515125206537021126 0ustar nileshnileshpackage buffer import ( "regexp" "unicode/utf8" "github.com/zyedidia/micro/v2/internal/util" ) // We want "^" and "$" to match only the beginning/end of a line, not the // beginning/end of the search region if it is in the middle of a line. // In that case we use padded regexps to require a rune before or after // the match. (This also affects other empty-string patters like "\\b".) // The following two flags indicate the padding used. const ( padStart = 1 << iota padEnd ) func findLineParams(b *Buffer, start, end Loc, i int, r *regexp.Regexp) ([]byte, int, int, *regexp.Regexp) { l := b.LineBytes(i) charpos := 0 padMode := 0 if i == end.Y { nchars := util.CharacterCount(l) end.X = util.Clamp(end.X, 0, nchars) if end.X < nchars { l = util.SliceStart(l, end.X+1) padMode |= padEnd } } if i == start.Y { nchars := util.CharacterCount(l) start.X = util.Clamp(start.X, 0, nchars) if start.X > 0 { charpos = start.X - 1 l = util.SliceEnd(l, charpos) padMode |= padStart } } if padMode != 0 { re, err := regexp.Compile(r.String() + `\E`) if err == nil { // r contains \Q without closing \E r = re } if padMode == padStart { r = regexp.MustCompile(".(?:" + r.String() + ")") } else if padMode == padEnd { r = regexp.MustCompile("(?:" + r.String() + ").") } else { // padMode == padStart|padEnd r = regexp.MustCompile(".(?:" + r.String() + ").") } } return l, charpos, padMode, r } func (b *Buffer) findDown(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) { lastcn := util.CharacterCount(b.LineBytes(b.LinesNum() - 1)) if start.Y > b.LinesNum()-1 { start.X = lastcn - 1 } if end.Y > b.LinesNum()-1 { end.X = lastcn } start.Y = util.Clamp(start.Y, 0, b.LinesNum()-1) end.Y = util.Clamp(end.Y, 0, b.LinesNum()-1) if start.GreaterThan(end) { start, end = end, start } for i := start.Y; i <= end.Y; i++ { l, charpos, padMode, rPadded := findLineParams(b, start, end, i, r) match := rPadded.FindIndex(l) if match != nil { if padMode&padStart != 0 { _, size := utf8.DecodeRune(l[match[0]:]) match[0] += size } if padMode&padEnd != 0 { _, size := utf8.DecodeLastRune(l[:match[1]]) match[1] -= size } start := Loc{charpos + util.RunePos(l, match[0]), i} end := Loc{charpos + util.RunePos(l, match[1]), i} return [2]Loc{start, end}, true } } return [2]Loc{}, false } func (b *Buffer) findUp(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) { lastcn := util.CharacterCount(b.LineBytes(b.LinesNum() - 1)) if start.Y > b.LinesNum()-1 { start.X = lastcn - 1 } if end.Y > b.LinesNum()-1 { end.X = lastcn } start.Y = util.Clamp(start.Y, 0, b.LinesNum()-1) end.Y = util.Clamp(end.Y, 0, b.LinesNum()-1) if start.GreaterThan(end) { start, end = end, start } for i := end.Y; i >= start.Y; i-- { charCount := util.CharacterCount(b.LineBytes(i)) from := Loc{0, i}.Clamp(start, end) to := Loc{charCount, i}.Clamp(start, end) allMatches := b.findAll(r, from, to) if allMatches != nil { match := allMatches[len(allMatches)-1] return [2]Loc{match[0], match[1]}, true } } return [2]Loc{}, false } func (b *Buffer) findAll(r *regexp.Regexp, start, end Loc) [][2]Loc { var matches [][2]Loc loc := start for { match, found := b.findDown(r, loc, end) if !found { break } matches = append(matches, match) if match[0] != match[1] { loc = match[1] } else if match[1] != end { loc = match[1].Move(1, b) } else { break } } return matches } // FindNext finds the next occurrence of a given string in the buffer // It returns the start and end location of the match (if found) and // a boolean indicating if it was found // May also return an error if the search regex is invalid func (b *Buffer) FindNext(s string, start, end, from Loc, down bool, useRegex bool) ([2]Loc, bool, error) { if s == "" { return [2]Loc{}, false, nil } var r *regexp.Regexp var err error if !useRegex { s = regexp.QuoteMeta(s) } if b.Settings["ignorecase"].(bool) { r, err = regexp.Compile("(?i)" + s) } else { r, err = regexp.Compile(s) } if err != nil { return [2]Loc{}, false, err } var found bool var l [2]Loc if down { l, found = b.findDown(r, from, end) if !found { l, found = b.findDown(r, start, end) } } else { l, found = b.findUp(r, from, start) if !found { l, found = b.findUp(r, end, start) } } return l, found, nil } // ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area // and returns the number of replacements made and the number of characters // added or removed on the last line of the range func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []byte, captureGroups bool) (int, int) { if start.GreaterThan(end) { start, end = end, start } charsEnd := util.CharacterCount(b.LineBytes(end.Y)) found := 0 var deltas []Delta for i := start.Y; i <= end.Y; i++ { l := b.LineBytes(i) charCount := util.CharacterCount(l) if (i == start.Y && start.X > 0) || (i == end.Y && end.X < charCount) { // This replacement code works in general, but it creates a separate // modification for each match. We only use it for the first and last // lines, which may use padded regexps from := Loc{0, i}.Clamp(start, end) to := Loc{charCount, i}.Clamp(start, end) matches := b.findAll(search, from, to) found += len(matches) for j := len(matches) - 1; j >= 0; j-- { // if we counted upwards, the different deltas would interfere match := matches[j] var newText []byte if captureGroups { newText = search.ReplaceAll(b.Substr(match[0], match[1]), replace) } else { newText = replace } deltas = append(deltas, Delta{newText, match[0], match[1]}) } } else { newLine := search.ReplaceAllFunc(l, func(in []byte) []byte { found++ var result []byte if captureGroups { match := search.FindSubmatchIndex(in) result = search.Expand(result, replace, in, match) } else { result = replace } return result }) deltas = append(deltas, Delta{newLine, Loc{0, i}, Loc{charCount, i}}) } } b.MultipleReplace(deltas) return found, util.CharacterCount(b.LineBytes(end.Y)) - charsEnd } zyedidia-micro-6a62575/internal/buffer/save.go0000664000175000017510000002223515125206537020621 0ustar nileshnileshpackage buffer import ( "bufio" "bytes" "errors" "io" "io/fs" "os" "os/exec" "os/signal" "path/filepath" "runtime" "time" "unicode" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" "golang.org/x/text/transform" ) // LargeFileThreshold is the number of bytes when fastdirty is forced // because hashing is too slow const LargeFileThreshold = 50000 type wrappedFile struct { name string writeCloser io.WriteCloser withSudo bool screenb bool cmd *exec.Cmd sigChan chan os.Signal } type saveResponse struct { size int err error } type saveRequest struct { buf *Buffer path string withSudo bool newFile bool saveResponseChan chan saveResponse } var saveRequestChan chan saveRequest var backupRequestChan chan backupRequest func init() { // Both saveRequestChan and backupRequestChan need to be non-buffered // so the save/backup goroutine receives both save and backup requests // in the same order the main goroutine sends them. saveRequestChan = make(chan saveRequest) backupRequestChan = make(chan backupRequest) go func() { duration := backupSeconds * float64(time.Second) backupTicker := time.NewTicker(time.Duration(duration)) for { select { case sr := <-saveRequestChan: size, err := sr.buf.safeWrite(sr.path, sr.withSudo, sr.newFile) sr.saveResponseChan <- saveResponse{size, err} case br := <-backupRequestChan: handleBackupRequest(br) case <-backupTicker.C: periodicBackup() } } }() } func openFile(name string, withSudo bool) (wrappedFile, error) { var err error var writeCloser io.WriteCloser var screenb bool var cmd *exec.Cmd var sigChan chan os.Signal if withSudo { conv := "notrunc" // TODO: both platforms do not support dd with conv=fsync yet if !(runtime.GOOS == "illumos" || runtime.GOOS == "netbsd") { conv += ",fsync" } cmd = exec.Command(config.GlobalSettings["sucmd"].(string), "dd", "bs=4k", "conv="+conv, "of="+name) writeCloser, err = cmd.StdinPipe() if err != nil { return wrappedFile{}, err } sigChan = make(chan os.Signal, 1) signal.Reset(os.Interrupt) signal.Notify(sigChan, os.Interrupt) screenb = screen.TempFini() // need to start the process now, otherwise when we flush the file // contents to its stdin it might hang because the kernel's pipe size // is too small to handle the full file contents all at once err = cmd.Start() if err != nil { screen.TempStart(screenb) signal.Notify(util.Sigterm, os.Interrupt) signal.Stop(sigChan) return wrappedFile{}, err } } else { writeCloser, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE, util.FileMode) if err != nil { return wrappedFile{}, err } } return wrappedFile{name, writeCloser, withSudo, screenb, cmd, sigChan}, nil } func (wf wrappedFile) Truncate() error { if wf.withSudo { // we don't need to stop the screen here, since it is still stopped // by openFile() // truncate might not be available on every platfom, so use dd instead cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "dd", "count=0", "of="+wf.name) return cmd.Run() } return wf.writeCloser.(*os.File).Truncate(0) } func (wf wrappedFile) Write(b *SharedBuffer) (int, error) { file := bufio.NewWriter(transform.NewWriter(wf.writeCloser, b.encoding.NewEncoder())) b.Lock() defer b.Unlock() if len(b.lines) == 0 { return 0, nil } // end of line var eol []byte if b.Endings == FFDos { eol = []byte{'\r', '\n'} } else { eol = []byte{'\n'} } err := wf.Truncate() if err != nil { return 0, err } // write lines size, err := file.Write(b.lines[0].data) if err != nil { return 0, err } for _, l := range b.lines[1:] { if _, err = file.Write(eol); err != nil { return 0, err } if _, err = file.Write(l.data); err != nil { return 0, err } size += len(eol) + len(l.data) } err = file.Flush() if err == nil && !wf.withSudo { // Call Sync() on the file to make sure the content is safely on disk. f := wf.writeCloser.(*os.File) err = f.Sync() } return size, err } func (wf wrappedFile) Close() error { err := wf.writeCloser.Close() if wf.withSudo { // wait for dd to finish and restart the screen if we used sudo err := wf.cmd.Wait() screen.TempStart(wf.screenb) signal.Notify(util.Sigterm, os.Interrupt) signal.Stop(wf.sigChan) if err != nil { return err } } return err } func (b *SharedBuffer) overwriteFile(name string) (int, error) { file, err := openFile(name, false) if err != nil { return 0, err } size, err := file.Write(b) err2 := file.Close() if err2 != nil && err == nil { err = err2 } return size, err } // Save saves the buffer to its default path func (b *Buffer) Save() error { return b.SaveAs(b.Path) } // AutoSave saves the buffer to its default path func (b *Buffer) AutoSave() error { if !b.Modified() { return nil } return b.saveToFile(b.Path, false, true) } // SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist func (b *Buffer) SaveAs(filename string) error { return b.saveToFile(filename, false, false) } func (b *Buffer) SaveWithSudo() error { return b.SaveAsWithSudo(b.Path) } func (b *Buffer) SaveAsWithSudo(filename string) error { return b.saveToFile(filename, true, false) } func (b *Buffer) saveToFile(filename string, withSudo bool, autoSave bool) error { var err error if b.Type.Readonly { return errors.New("Cannot save readonly buffer") } if b.Type.Scratch { return errors.New("Cannot save scratch buffer") } if !autoSave && b.Settings["rmtrailingws"].(bool) { for i, l := range b.lines { leftover := util.CharacterCount(bytes.TrimRightFunc(l.data, unicode.IsSpace)) linelen := util.CharacterCount(l.data) b.Remove(Loc{leftover, i}, Loc{linelen, i}) } b.RelocateCursors() } if b.Settings["eofnewline"].(bool) { end := b.End() if b.RuneAt(Loc{end.X - 1, end.Y}) != '\n' { b.insert(end, []byte{'\n'}) } } filename, err = util.ReplaceHome(filename) if err != nil { return err } newFile := false fileInfo, err := os.Stat(filename) if err != nil { if !errors.Is(err, fs.ErrNotExist) { return err } newFile = true } if err == nil && fileInfo.IsDir() { return errors.New("Error: " + filename + " is a directory and cannot be saved") } if err == nil && !fileInfo.Mode().IsRegular() { return errors.New("Error: " + filename + " is not a regular file and cannot be saved") } absFilename, err := filepath.Abs(filename) if err != nil { return err } // Get the leading path to the file | "." is returned if there's no leading path provided if dirname := filepath.Dir(absFilename); dirname != "." { // Check if the parent dirs don't exist if _, statErr := os.Stat(dirname); errors.Is(statErr, fs.ErrNotExist) { // Prompt to make sure they want to create the dirs that are missing if b.Settings["mkparents"].(bool) { // Create all leading dir(s) since they don't exist if mkdirallErr := os.MkdirAll(dirname, os.ModePerm); mkdirallErr != nil { // If there was an error creating the dirs return mkdirallErr } } else { return errors.New("Parent dirs don't exist, enable 'mkparents' for auto creation") } } } saveResponseChan := make(chan saveResponse) saveRequestChan <- saveRequest{b, absFilename, withSudo, newFile, saveResponseChan} result := <-saveResponseChan err = result.err if err != nil { if errors.Is(err, util.ErrOverwrite) { screen.TermMessage(err) err = errors.Unwrap(err) b.UpdateModTime() } return err } if !b.Settings["fastdirty"].(bool) { if result.size > LargeFileThreshold { // For large files 'fastdirty' needs to be on b.Settings["fastdirty"] = true } else { b.calcHash(&b.origHash) } } newPath := b.Path != filename if newPath { b.RemoveBackup() } b.Path = filename b.AbsPath = absFilename b.isModified = false b.UpdateModTime() if newPath { // need to update glob-based and filetype-based settings b.ReloadSettings(true) } err = b.Serialize() return err } // safeWrite writes the buffer to a file in a "safe" way, preventing loss of the // contents of the file if it fails to write the new contents. // This means that the file is not overwritten directly but by writing to the // backup file first. func (b *SharedBuffer) safeWrite(path string, withSudo bool, newFile bool) (int, error) { file, err := openFile(path, withSudo) if err != nil { return 0, err } defer func() { if newFile && err != nil { os.Remove(path) } }() // Try to backup first before writing backupName, resolveName, err := b.writeBackup(path) if err != nil { file.Close() return 0, err } // Backup saved, so cancel pending periodic backup, if any delete(requestedBackups, b) b.forceKeepBackup = true size := 0 { // If we failed to write or close, keep the backup we made size, err = file.Write(b) if err != nil { file.Close() return 0, util.OverwriteError{err, backupName} } err = file.Close() if err != nil { return 0, util.OverwriteError{err, backupName} } } b.forceKeepBackup = false if !b.keepBackup() { b.removeBackup(backupName, resolveName) } return size, err } zyedidia-micro-6a62575/internal/buffer/message.go0000664000175000017510000000352015125206537021303 0ustar nileshnileshpackage buffer import ( "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/config" ) type MsgType int const ( MTInfo = iota MTWarning MTError ) // Message represents the information for a gutter message type Message struct { // The Msg iteslf Msg string // Start and End locations for the message Start, End Loc // The Kind stores the message type Kind MsgType // The Owner of the message Owner string } // NewMessage creates a new gutter message func NewMessage(owner string, msg string, start, end Loc, kind MsgType) *Message { return &Message{ Msg: msg, Start: start, End: end, Kind: kind, Owner: owner, } } // NewMessageAtLine creates a new gutter message at a given line func NewMessageAtLine(owner string, msg string, line int, kind MsgType) *Message { start := Loc{-1, line - 1} end := start return NewMessage(owner, msg, start, end, kind) } func (m *Message) Style() tcell.Style { switch m.Kind { case MTInfo: if style, ok := config.Colorscheme["gutter-info"]; ok { return style } case MTWarning: if style, ok := config.Colorscheme["gutter-warning"]; ok { return style } case MTError: if style, ok := config.Colorscheme["gutter-error"]; ok { return style } } return config.DefStyle } func (b *Buffer) AddMessage(m *Message) { b.Messages = append(b.Messages, m) } func (b *Buffer) removeMsg(i int) { copy(b.Messages[i:], b.Messages[i+1:]) b.Messages[len(b.Messages)-1] = nil b.Messages = b.Messages[:len(b.Messages)-1] } func (b *Buffer) ClearMessages(owner string) { for i := len(b.Messages) - 1; i >= 0; i-- { if b.Messages[i].Owner == owner { b.removeMsg(i) } } } func (b *Buffer) ClearAllMessages() { b.Messages = make([]*Message, 0) } type Messager interface { Message(msg ...any) } var prompt Messager func SetMessager(m Messager) { prompt = m } zyedidia-micro-6a62575/internal/buffer/loc.go0000664000175000017510000000600215125206537020432 0ustar nileshnileshpackage buffer import ( "github.com/zyedidia/micro/v2/internal/util" ) // Loc stores a location type Loc struct { X, Y int } // LessThan returns true if b is smaller func (l Loc) LessThan(b Loc) bool { if l.Y < b.Y { return true } return l.Y == b.Y && l.X < b.X } // GreaterThan returns true if b is bigger func (l Loc) GreaterThan(b Loc) bool { if l.Y > b.Y { return true } return l.Y == b.Y && l.X > b.X } // GreaterEqual returns true if b is greater than or equal to b func (l Loc) GreaterEqual(b Loc) bool { if l.Y > b.Y { return true } if l.Y == b.Y && l.X > b.X { return true } return l == b } // LessEqual returns true if b is less than or equal to b func (l Loc) LessEqual(b Loc) bool { if l.Y < b.Y { return true } if l.Y == b.Y && l.X < b.X { return true } return l == b } // Clamp clamps a loc between start and end func (l Loc) Clamp(start, end Loc) Loc { if l.GreaterEqual(end) { return end } else if l.LessThan(start) { return start } return l } // The following functions require a buffer to know where newlines are // Diff returns the distance between two locations func DiffLA(a, b Loc, buf *LineArray) int { if a.Y == b.Y { if a.X > b.X { return a.X - b.X } return b.X - a.X } // Make sure a is guaranteed to be less than b if b.LessThan(a) { a, b = b, a } loc := 0 for i := a.Y + 1; i < b.Y; i++ { // + 1 for the newline loc += util.CharacterCount(buf.LineBytes(i)) + 1 } loc += util.CharacterCount(buf.LineBytes(a.Y)) - a.X + b.X + 1 return loc } // This moves the location one character to the right func (l Loc) right(buf *LineArray) Loc { if l == buf.End() { return Loc{l.X + 1, l.Y} } var res Loc if l.X < util.CharacterCount(buf.LineBytes(l.Y)) { res = Loc{l.X + 1, l.Y} } else { res = Loc{0, l.Y + 1} } return res } // This moves the given location one character to the left func (l Loc) left(buf *LineArray) Loc { if l == buf.Start() { return Loc{l.X - 1, l.Y} } var res Loc if l.X > 0 { res = Loc{l.X - 1, l.Y} } else { res = Loc{util.CharacterCount(buf.LineBytes(l.Y - 1)), l.Y - 1} } return res } // MoveLA moves the cursor n characters to the left or right // It moves the cursor left if n is negative func (l Loc) MoveLA(n int, buf *LineArray) Loc { if n > 0 { for i := 0; i < n; i++ { l = l.right(buf) } return l } for i := 0; i < util.Abs(n); i++ { l = l.left(buf) } return l } // Diff returns the difference between two locs func (l Loc) Diff(b Loc, buf *Buffer) int { return DiffLA(l, b, buf.LineArray) } // Move moves a loc n characters func (l Loc) Move(n int, buf *Buffer) Loc { return l.MoveLA(n, buf.LineArray) } // ByteOffset is just like ToCharPos except it counts bytes instead of runes func ByteOffset(pos Loc, buf *Buffer) int { x, y := pos.X, pos.Y loc := 0 for i := 0; i < y; i++ { // + 1 for the newline loc += len(buf.Line(i)) + 1 } loc += len(buf.Line(y)[:x]) return loc } // clamps a loc within a buffer func clamp(pos Loc, la *LineArray) Loc { return pos.Clamp(la.Start(), la.End()) } zyedidia-micro-6a62575/internal/buffer/line_array_test.go0000664000175000017510000000352315125206537023046 0ustar nileshnileshpackage buffer import ( "strings" "testing" "github.com/stretchr/testify/assert" ) var unicode_txt = `An preost wes on leoden, LaÈamon was ihoten He wes Leovenaðes sone -- liðe him be Drihten. He wonede at ErnleÈe at æðelen are chirechen, Uppen Sevarne staþe, sel þar him þuhte, Onfest Radestone, þer he bock radde.` var la *LineArray func init() { reader := strings.NewReader(unicode_txt) la = NewLineArray(uint64(len(unicode_txt)), FFAuto, reader) } func TestSplit(t *testing.T) { la.insert(Loc{17, 1}, []byte{'\n'}) assert.Equal(t, len(la.lines), 6) sub1 := la.Substr(Loc{0, 1}, Loc{17, 1}) sub2 := la.Substr(Loc{0, 2}, Loc{30, 2}) assert.Equal(t, []byte("He wes Leovenaðes"), sub1) assert.Equal(t, []byte(" sone -- liðe him be Drihten."), sub2) } func TestJoin(t *testing.T) { la.remove(Loc{47, 1}, Loc{0, 2}) assert.Equal(t, len(la.lines), 5) sub := la.Substr(Loc{0, 1}, Loc{47, 1}) bytes := la.Bytes() assert.Equal(t, []byte("He wes Leovenaðes sone -- liðe him be Drihten."), sub) assert.Equal(t, unicode_txt, string(bytes)) } func TestInsert(t *testing.T) { la.insert(Loc{20, 3}, []byte(" foobar")) sub1 := la.Substr(Loc{0, 3}, Loc{50, 3}) assert.Equal(t, []byte("Uppen Sevarne staþe, foobar sel þar him þuhte,"), sub1) la.insert(Loc{25, 2}, []byte("H̼̥̯͇͙̕͘͞e̸̦̞̠̣̰͙̼̥̦̼̖̬͕͕̰̯̫͇̕ĺ̜̠̩̯̯͙̼̭̠͕̮̞͜l̶͓̫̞̮͈͞ͅo̸͔͙̳̠͈̮̼̳͙̥̲͜͠")) sub2 := la.Substr(Loc{0, 2}, Loc{60, 2}) assert.Equal(t, []byte("He wonede at ErnleÈe at æH̼̥̯͇͙̕͘͞e̸̦̞̠̣̰͙̼̥̦̼̖̬͕͕̰̯̫͇̕ĺ̜̠̩̯̯͙̼̭̠͕̮̞͜l̶͓̫̞̮͈͞ͅo̸͔͙̳̠͈̮̼̳͙̥̲͜͠ðelen are chirechen,"), sub2) } func TestRemove(t *testing.T) { la.remove(Loc{20, 3}, Loc{27, 3}) la.remove(Loc{25, 2}, Loc{30, 2}) bytes := la.Bytes() assert.Equal(t, unicode_txt, string(bytes)) } zyedidia-micro-6a62575/internal/buffer/line_array.go0000664000175000017510000002675415125206537022022 0ustar nileshnileshpackage buffer import ( "bufio" "bytes" "io" "sync" "github.com/zyedidia/micro/v2/internal/util" "github.com/zyedidia/micro/v2/pkg/highlight" ) // Finds the byte index of the nth rune in a byte slice func runeToByteIndex(n int, txt []byte) int { if n == 0 { return 0 } count := 0 i := 0 for len(txt) > 0 { _, _, size := util.DecodeCharacter(txt) txt = txt[size:] count += size i++ if i == n { break } } return count } // A searchState contains the search match info for a single line type searchState struct { search string useRegex bool ignorecase bool match [][2]int done bool } // A Line contains the data in bytes as well as a highlight state, match // and a flag for whether the highlighting needs to be updated type Line struct { data []byte state highlight.State match highlight.LineMatch lock sync.Mutex // The search states for the line, used for highlighting of search matches, // separately from the syntax highlighting. // A map is used because the line array may be shared between multiple buffers // (multiple instances of the same file opened in different edit panes) // which have distinct searches, so in the general case there are multiple // searches per a line, one search per a Buffer containing this line. search map[*Buffer]*searchState } const ( // Line ending file formats FFAuto = 0 // Autodetect format FFUnix = 1 // LF line endings (unix style '\n') FFDos = 2 // CRLF line endings (dos style '\r\n') ) type FileFormat byte // A LineArray simply stores and array of lines and makes it easy to insert // and delete in it type LineArray struct { lines []Line Endings FileFormat initsize uint64 lock sync.Mutex } // Append efficiently appends lines together // It allocates an additional 10000 lines if the original estimate // is incorrect func Append(slice []Line, data ...Line) []Line { l := len(slice) if l+len(data) > cap(slice) { // reallocate newSlice := make([]Line, (l+len(data))+10000) copy(newSlice, slice) slice = newSlice } slice = slice[0 : l+len(data)] for i, c := range data { slice[l+i] = c } return slice } // NewLineArray returns a new line array from an array of bytes func NewLineArray(size uint64, endings FileFormat, reader io.Reader) *LineArray { la := new(LineArray) la.lines = make([]Line, 0, 1000) la.initsize = size br := bufio.NewReader(reader) var loaded int la.Endings = endings n := 0 for { data, err := br.ReadBytes('\n') // Detect the line ending by checking to see if there is a '\r' char // before the '\n' // Even if the file format is set to DOS, the '\r' is removed so // that all lines end with '\n' dlen := len(data) if dlen > 1 && data[dlen-2] == '\r' { data = append(data[:dlen-2], '\n') if la.Endings == FFAuto { la.Endings = FFDos } dlen = len(data) } else if dlen > 0 { if la.Endings == FFAuto { la.Endings = FFUnix } } // If we are loading a large file (greater than 1000) we use the file // size and the length of the first 1000 lines to try to estimate // how many lines will need to be allocated for the rest of the file // We add an extra 10000 to the original estimate to be safe and give // plenty of room for expansion if n >= 1000 && loaded >= 0 { totalLinesNum := int(float64(size) * (float64(n) / float64(loaded))) newSlice := make([]Line, len(la.lines), totalLinesNum+10000) copy(newSlice, la.lines) la.lines = newSlice loaded = -1 } // Counter for the number of bytes in the first 1000 lines if loaded >= 0 { loaded += dlen } if err != nil { if err == io.EOF { la.lines = Append(la.lines, Line{ data: data, state: nil, match: nil, }) } // Last line was read break } else { la.lines = Append(la.lines, Line{ data: data[:dlen-1], state: nil, match: nil, }) } n++ } return la } // Bytes returns the string that should be written to disk when // the line array is saved func (la *LineArray) Bytes() []byte { b := new(bytes.Buffer) // initsize should provide a good estimate b.Grow(int(la.initsize + 4096)) for i, l := range la.lines { b.Write(l.data) if i != len(la.lines)-1 { if la.Endings == FFDos { b.WriteByte('\r') } b.WriteByte('\n') } } return b.Bytes() } // newlineBelow adds a newline below the given line number func (la *LineArray) newlineBelow(y int) { la.lines = append(la.lines, Line{ data: []byte{' '}, state: nil, match: nil, }) copy(la.lines[y+2:], la.lines[y+1:]) la.lines[y+1] = Line{ data: []byte{}, state: la.lines[y].state, match: nil, } } // Inserts a byte array at a given location func (la *LineArray) insert(pos Loc, value []byte) { la.lock.Lock() defer la.lock.Unlock() x, y := runeToByteIndex(pos.X, la.lines[pos.Y].data), pos.Y for i := 0; i < len(value); i++ { if value[i] == '\n' || (value[i] == '\r' && i < len(value)-1 && value[i+1] == '\n') { la.split(Loc{x, y}) x = 0 y++ if value[i] == '\r' { i++ } continue } la.insertByte(Loc{x, y}, value[i]) x++ } } // InsertByte inserts a byte at a given location func (la *LineArray) insertByte(pos Loc, value byte) { la.lines[pos.Y].data = append(la.lines[pos.Y].data, 0) copy(la.lines[pos.Y].data[pos.X+1:], la.lines[pos.Y].data[pos.X:]) la.lines[pos.Y].data[pos.X] = value } // joinLines joins the two lines a and b func (la *LineArray) joinLines(a, b int) { la.lines[a].data = append(la.lines[a].data, la.lines[b].data...) la.deleteLine(b) } // split splits a line at a given position func (la *LineArray) split(pos Loc) { la.newlineBelow(pos.Y) la.lines[pos.Y+1].data = append(la.lines[pos.Y+1].data, la.lines[pos.Y].data[pos.X:]...) la.lines[pos.Y+1].state = la.lines[pos.Y].state la.lines[pos.Y].state = nil la.lines[pos.Y].match = nil la.lines[pos.Y+1].match = nil la.deleteToEnd(Loc{pos.X, pos.Y}) } // removes from start to end func (la *LineArray) remove(start, end Loc) []byte { la.lock.Lock() defer la.lock.Unlock() sub := la.Substr(start, end) startX := runeToByteIndex(start.X, la.lines[start.Y].data) endX := runeToByteIndex(end.X, la.lines[end.Y].data) if start.Y == end.Y { la.lines[start.Y].data = append(la.lines[start.Y].data[:startX], la.lines[start.Y].data[endX:]...) } else { la.deleteLines(start.Y+1, end.Y-1) la.deleteToEnd(Loc{startX, start.Y}) la.deleteFromStart(Loc{endX - 1, start.Y + 1}) la.joinLines(start.Y, start.Y+1) } return sub } // deleteToEnd deletes from the end of a line to the position func (la *LineArray) deleteToEnd(pos Loc) { la.lines[pos.Y].data = la.lines[pos.Y].data[:pos.X] } // deleteFromStart deletes from the start of a line to the position func (la *LineArray) deleteFromStart(pos Loc) { la.lines[pos.Y].data = la.lines[pos.Y].data[pos.X+1:] } // deleteLine deletes the line number func (la *LineArray) deleteLine(y int) { la.lines = la.lines[:y+copy(la.lines[y:], la.lines[y+1:])] } func (la *LineArray) deleteLines(y1, y2 int) { la.lines = la.lines[:y1+copy(la.lines[y1:], la.lines[y2+1:])] } // Substr returns the string representation between two locations func (la *LineArray) Substr(start, end Loc) []byte { startX := runeToByteIndex(start.X, la.lines[start.Y].data) endX := runeToByteIndex(end.X, la.lines[end.Y].data) if start.Y == end.Y { src := la.lines[start.Y].data[startX:endX] dest := make([]byte, len(src)) copy(dest, src) return dest } str := make([]byte, 0, len(la.lines[start.Y+1].data)*(end.Y-start.Y)) str = append(str, la.lines[start.Y].data[startX:]...) str = append(str, '\n') for i := start.Y + 1; i <= end.Y-1; i++ { str = append(str, la.lines[i].data...) str = append(str, '\n') } str = append(str, la.lines[end.Y].data[:endX]...) return str } // LinesNum returns the number of lines in the buffer func (la *LineArray) LinesNum() int { return len(la.lines) } // Start returns the start of the buffer func (la *LineArray) Start() Loc { return Loc{0, 0} } // End returns the location of the last character in the buffer func (la *LineArray) End() Loc { numlines := len(la.lines) return Loc{util.CharacterCount(la.lines[numlines-1].data), numlines - 1} } // LineBytes returns line n as an array of bytes func (la *LineArray) LineBytes(lineN int) []byte { if lineN >= len(la.lines) || lineN < 0 { return []byte{} } return la.lines[lineN].data } // State gets the highlight state for the given line number func (la *LineArray) State(lineN int) highlight.State { la.lines[lineN].lock.Lock() defer la.lines[lineN].lock.Unlock() return la.lines[lineN].state } // SetState sets the highlight state at the given line number func (la *LineArray) SetState(lineN int, s highlight.State) { la.lines[lineN].lock.Lock() defer la.lines[lineN].lock.Unlock() la.lines[lineN].state = s } // SetMatch sets the match at the given line number func (la *LineArray) SetMatch(lineN int, m highlight.LineMatch) { la.lines[lineN].lock.Lock() defer la.lines[lineN].lock.Unlock() la.lines[lineN].match = m } // Match retrieves the match for the given line number func (la *LineArray) Match(lineN int) highlight.LineMatch { la.lines[lineN].lock.Lock() defer la.lines[lineN].lock.Unlock() return la.lines[lineN].match } // Locks the whole LineArray func (la *LineArray) Lock() { la.lock.Lock() } // Unlocks the whole LineArray func (la *LineArray) Unlock() { la.lock.Unlock() } // SearchMatch returns true if the location `pos` is within a match // of the last search for the buffer `b`. // It is used for efficient highlighting of search matches (separately // from the syntax highlighting). // SearchMatch searches for the matches if it is called first time // for the given line or if the line was modified. Otherwise the // previously found matches are used. // // The buffer `b` needs to be passed because the line array may be shared // between multiple buffers (multiple instances of the same file opened // in different edit panes) which have distinct searches, so SearchMatch // needs to know which search to match against. func (la *LineArray) SearchMatch(b *Buffer, pos Loc) bool { if b.LastSearch == "" { return false } lineN := pos.Y if la.lines[lineN].search == nil { la.lines[lineN].search = make(map[*Buffer]*searchState) } s, ok := la.lines[lineN].search[b] if !ok { // Note: here is a small harmless leak: when the buffer `b` is closed, // `s` is not deleted from the map. It means that the buffer // will not be garbage-collected until the line array is garbage-collected, // i.e. until all the buffers sharing this file are closed. s = new(searchState) la.lines[lineN].search[b] = s } if !ok || s.search != b.LastSearch || s.useRegex != b.LastSearchRegex || s.ignorecase != b.Settings["ignorecase"].(bool) { s.search = b.LastSearch s.useRegex = b.LastSearchRegex s.ignorecase = b.Settings["ignorecase"].(bool) s.done = false } if !s.done { s.match = nil start := Loc{0, lineN} end := Loc{util.CharacterCount(la.lines[lineN].data), lineN} for start.X < end.X { m, found, _ := b.FindNext(b.LastSearch, start, end, start, true, b.LastSearchRegex) if !found { break } s.match = append(s.match, [2]int{m[0].X, m[1].X}) start.X = m[1].X if m[1].X == m[0].X { start.X = m[1].X + 1 } } s.done = true } for _, m := range s.match { if pos.X >= m[0] && pos.X < m[1] { return true } } return false } // invalidateSearchMatches marks search matches for the given line as outdated. // It is called when the line is modified. func (la *LineArray) invalidateSearchMatches(lineN int) { if la.lines[lineN].search != nil { for _, s := range la.lines[lineN].search { s.done = false } } } zyedidia-micro-6a62575/internal/buffer/eventhandler.go0000664000175000017510000002366715125206537022354 0ustar nileshnileshpackage buffer import ( "bytes" "time" dmp "github.com/sergi/go-diff/diffmatchpatch" "github.com/zyedidia/micro/v2/internal/config" ulua "github.com/zyedidia/micro/v2/internal/lua" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" luar "layeh.com/gopher-luar" ) const ( // Opposite and undoing events must have opposite values // TextEventInsert represents an insertion event TextEventInsert = 1 // TextEventRemove represents a deletion event TextEventRemove = -1 // TextEventReplace represents a replace event TextEventReplace = 0 undoThreshold = 1000 // If two events are less than n milliseconds apart, undo both of them ) // TextEvent holds data for a manipulation on some text that can be undone type TextEvent struct { C Cursor EventType int Deltas []Delta Time time.Time } // A Delta is a change to the buffer type Delta struct { Text []byte Start Loc End Loc } // DoTextEvent runs a text event func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) { oldl := eh.buf.LinesNum() if useUndo { eh.Execute(t) } else { ExecuteTextEvent(t, eh.buf) } if len(t.Deltas) != 1 { return } text := t.Deltas[0].Text start := t.Deltas[0].Start lastnl := -1 var endX int var textX int if t.EventType == TextEventInsert { linecount := eh.buf.LinesNum() - oldl textcount := util.CharacterCount(text) lastnl = bytes.LastIndex(text, []byte{'\n'}) if lastnl >= 0 { endX = util.CharacterCount(text[lastnl+1:]) textX = endX } else { endX = start.X + textcount textX = textcount } t.Deltas[0].End = clamp(Loc{endX, start.Y + linecount}, eh.buf.LineArray) } end := t.Deltas[0].End for _, c := range eh.cursors { move := func(loc Loc) Loc { if t.EventType == TextEventInsert { if start.Y != loc.Y && loc.GreaterThan(start) { loc.Y += end.Y - start.Y } else if loc.Y == start.Y && loc.GreaterEqual(start) { loc.Y += end.Y - start.Y if lastnl >= 0 { loc.X += textX - start.X } else { loc.X += textX } } return loc } else { if loc.Y != end.Y && loc.GreaterThan(end) { loc.Y -= end.Y - start.Y } else if loc.Y == end.Y && loc.GreaterEqual(end) { loc = loc.MoveLA(-DiffLA(start, end, eh.buf.LineArray), eh.buf.LineArray) } return loc } } c.Loc = move(c.Loc) c.CurSelection[0] = move(c.CurSelection[0]) c.CurSelection[1] = move(c.CurSelection[1]) c.OrigSelection[0] = move(c.OrigSelection[0]) c.OrigSelection[1] = move(c.OrigSelection[1]) c.Relocate() c.StoreVisualX() } if useUndo { eh.updateTrailingWs(t) } } // ExecuteTextEvent runs a text event func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) { if t.EventType == TextEventInsert { for _, d := range t.Deltas { buf.insert(d.Start, d.Text) } } else if t.EventType == TextEventRemove { for i, d := range t.Deltas { t.Deltas[i].Text = buf.remove(d.Start, d.End) } } else if t.EventType == TextEventReplace { for i, d := range t.Deltas { t.Deltas[i].Text = buf.remove(d.Start, d.End) buf.insert(d.Start, d.Text) t.Deltas[i].Start = d.Start t.Deltas[i].End = Loc{d.Start.X + util.CharacterCount(d.Text), d.Start.Y} } for i, j := 0, len(t.Deltas)-1; i < j; i, j = i+1, j-1 { t.Deltas[i], t.Deltas[j] = t.Deltas[j], t.Deltas[i] } } } // UndoTextEvent undoes a text event func (eh *EventHandler) UndoTextEvent(t *TextEvent) { t.EventType = -t.EventType eh.DoTextEvent(t, false) } // EventHandler executes text manipulations and allows undoing and redoing type EventHandler struct { buf *SharedBuffer cursors []*Cursor active int UndoStack *TEStack RedoStack *TEStack } // NewEventHandler returns a new EventHandler func NewEventHandler(buf *SharedBuffer, cursors []*Cursor) *EventHandler { eh := new(EventHandler) eh.UndoStack = new(TEStack) eh.RedoStack = new(TEStack) eh.buf = buf eh.cursors = cursors return eh } // ApplyDiff takes a string and runs the necessary insertion and deletion events to make // the buffer equal to that string // This means that we can transform the buffer into any string and still preserve undo/redo // through insert and delete events func (eh *EventHandler) ApplyDiff(new string) { differ := dmp.New() diff := differ.DiffMain(string(eh.buf.Bytes()), new, false) loc := eh.buf.Start() for _, d := range diff { if d.Type == dmp.DiffDelete { eh.Remove(loc, loc.MoveLA(util.CharacterCountInString(d.Text), eh.buf.LineArray)) } else { if d.Type == dmp.DiffInsert { eh.Insert(loc, d.Text) } loc = loc.MoveLA(util.CharacterCountInString(d.Text), eh.buf.LineArray) } } } // Insert creates an insert text event and executes it func (eh *EventHandler) Insert(start Loc, textStr string) { text := []byte(textStr) eh.InsertBytes(start, text) } // InsertBytes creates an insert text event and executes it func (eh *EventHandler) InsertBytes(start Loc, text []byte) { if len(text) == 0 { return } start = clamp(start, eh.buf.LineArray) e := &TextEvent{ C: *eh.cursors[eh.active], EventType: TextEventInsert, Deltas: []Delta{{text, start, Loc{0, 0}}}, Time: time.Now(), } eh.DoTextEvent(e, true) } // Remove creates a remove text event and executes it func (eh *EventHandler) Remove(start, end Loc) { if start == end { return } start = clamp(start, eh.buf.LineArray) end = clamp(end, eh.buf.LineArray) e := &TextEvent{ C: *eh.cursors[eh.active], EventType: TextEventRemove, Deltas: []Delta{{[]byte{}, start, end}}, Time: time.Now(), } eh.DoTextEvent(e, true) } // MultipleReplace creates an multiple insertions executes them func (eh *EventHandler) MultipleReplace(deltas []Delta) { e := &TextEvent{ C: *eh.cursors[eh.active], EventType: TextEventReplace, Deltas: deltas, Time: time.Now(), } eh.Execute(e) } // Replace deletes from start to end and replaces it with the given string func (eh *EventHandler) Replace(start, end Loc, replace string) { eh.Remove(start, end) eh.Insert(start, replace) } // Execute a textevent and add it to the undo stack func (eh *EventHandler) Execute(t *TextEvent) { if eh.RedoStack.Len() > 0 { eh.RedoStack = new(TEStack) } eh.UndoStack.Push(t) b, err := config.RunPluginFnBool(nil, "onBeforeTextEvent", luar.New(ulua.L, eh.buf), luar.New(ulua.L, t)) if err != nil { screen.TermMessage(err) } if !b { return } ExecuteTextEvent(t, eh.buf) } // Undo the first event in the undo stack. Returns false if the stack is empty. func (eh *EventHandler) Undo() bool { t := eh.UndoStack.Peek() if t == nil { return false } startTime := t.Time.UnixNano() / int64(time.Millisecond) endTime := startTime - (startTime % undoThreshold) for { t = eh.UndoStack.Peek() if t == nil { break } if t.Time.UnixNano()/int64(time.Millisecond) < endTime { break } eh.UndoOneEvent() } return true } // UndoOneEvent undoes one event func (eh *EventHandler) UndoOneEvent() { // This event should be undone // Pop it off the stack t := eh.UndoStack.Pop() if t == nil { return } // Undo it // Modifies the text event eh.UndoTextEvent(t) // Set the cursor in the right place if t.C.Num >= 0 && t.C.Num < len(eh.cursors) { eh.cursors[t.C.Num].Goto(t.C) eh.cursors[t.C.Num].NewTrailingWsY = t.C.NewTrailingWsY } // Push it to the redo stack eh.RedoStack.Push(t) } // Redo the first event in the redo stack. Returns false if the stack is empty. func (eh *EventHandler) Redo() bool { t := eh.RedoStack.Peek() if t == nil { return false } startTime := t.Time.UnixNano() / int64(time.Millisecond) endTime := startTime - (startTime % undoThreshold) + undoThreshold for { t = eh.RedoStack.Peek() if t == nil { break } if t.Time.UnixNano()/int64(time.Millisecond) > endTime { break } eh.RedoOneEvent() } return true } // RedoOneEvent redoes one event func (eh *EventHandler) RedoOneEvent() { t := eh.RedoStack.Pop() if t == nil { return } if t.C.Num >= 0 && t.C.Num < len(eh.cursors) { eh.cursors[t.C.Num].Goto(t.C) eh.cursors[t.C.Num].NewTrailingWsY = t.C.NewTrailingWsY } // Modifies the text event eh.UndoTextEvent(t) eh.UndoStack.Push(t) } // updateTrailingWs updates the cursor's trailing whitespace status after a text event func (eh *EventHandler) updateTrailingWs(t *TextEvent) { if len(t.Deltas) != 1 { return } text := t.Deltas[0].Text start := t.Deltas[0].Start end := t.Deltas[0].End c := eh.cursors[eh.active] isEol := func(loc Loc) bool { return loc.X == util.CharacterCount(eh.buf.LineBytes(loc.Y)) } if t.EventType == TextEventInsert && c.Loc == end && isEol(end) { var addedTrailingWs bool addedAfterWs := false addedWsOnly := false if start.Y == end.Y { addedTrailingWs = util.HasTrailingWhitespace(text) addedWsOnly = util.IsBytesWhitespace(text) addedAfterWs = start.X > 0 && util.IsWhitespace(c.buf.RuneAt(Loc{start.X - 1, start.Y})) } else { lastnl := bytes.LastIndex(text, []byte{'\n'}) addedTrailingWs = util.HasTrailingWhitespace(text[lastnl+1:]) } if addedTrailingWs && !(addedAfterWs && addedWsOnly) { c.NewTrailingWsY = c.Y } else if !addedTrailingWs { c.NewTrailingWsY = -1 } } else if t.EventType == TextEventRemove && c.Loc == start && isEol(start) { removedAfterWs := util.HasTrailingWhitespace(eh.buf.LineBytes(start.Y)) var removedWsOnly bool if start.Y == end.Y { removedWsOnly = util.IsBytesWhitespace(text) } else { firstnl := bytes.Index(text, []byte{'\n'}) removedWsOnly = util.IsBytesWhitespace(text[:firstnl]) } if removedAfterWs && !removedWsOnly { c.NewTrailingWsY = c.Y } else if !removedAfterWs { c.NewTrailingWsY = -1 } } else if c.NewTrailingWsY != -1 && start.Y != end.Y && c.Loc.GreaterThan(start) && ((t.EventType == TextEventInsert && c.Y == c.NewTrailingWsY+(end.Y-start.Y)) || (t.EventType == TextEventRemove && c.Y == c.NewTrailingWsY-(end.Y-start.Y))) { // The cursor still has its new trailingws // but its line number was shifted by insert or remove of lines above c.NewTrailingWsY = c.Y } } zyedidia-micro-6a62575/internal/buffer/cursor.go0000664000175000017510000003436415125206537021206 0ustar nileshnileshpackage buffer import ( "github.com/zyedidia/micro/v2/internal/clipboard" "github.com/zyedidia/micro/v2/internal/util" ) // InBounds returns whether the given location is a valid character position in the given buffer func InBounds(pos Loc, buf *Buffer) bool { if pos.Y < 0 || pos.Y >= len(buf.lines) || pos.X < 0 || pos.X > util.CharacterCount(buf.LineBytes(pos.Y)) { return false } return true } // The Cursor struct stores the location of the cursor in the buffer // as well as the selection type Cursor struct { buf *Buffer Loc // Last visual x position of the cursor. Used in cursor up/down movements // for remembering the original x position when moving to a line that is // shorter than current x position. LastVisualX int // Similar to LastVisualX but takes softwrapping into account, i.e. last // visual x position in a visual (wrapped) line on the screen, which may be // different from the line in the buffer. LastWrappedVisualX int // The current selection as a range of character numbers (inclusive) CurSelection [2]Loc // The original selection as a range of character numbers // This is used for line and word selection where it is necessary // to know what the original selection was OrigSelection [2]Loc // The line number where a new trailing whitespace has been added // or -1 if there is no new trailing whitespace at this cursor. // This is used for checking if a trailing whitespace should be highlighted NewTrailingWsY int // Which cursor index is this (for multiple cursors) Num int } func NewCursor(b *Buffer, l Loc) *Cursor { c := &Cursor{ buf: b, Loc: l, NewTrailingWsY: -1, } c.StoreVisualX() return c } func (c *Cursor) SetBuf(b *Buffer) { c.buf = b } func (c *Cursor) Buf() *Buffer { return c.buf } // Goto puts the cursor at the given cursor's location and gives // the current cursor its selection too func (c *Cursor) Goto(b Cursor) { c.X, c.Y = b.X, b.Y c.OrigSelection, c.CurSelection = b.OrigSelection, b.CurSelection c.StoreVisualX() } // GotoLoc puts the cursor at the given cursor's location and gives // the current cursor its selection too func (c *Cursor) GotoLoc(l Loc) { c.X, c.Y = l.X, l.Y c.StoreVisualX() } // GetVisualX returns the x value of the cursor in visual spaces func (c *Cursor) GetVisualX(wrap bool) int { if wrap && c.buf.GetVisualX != nil { return c.buf.GetVisualX(c.Loc) } if c.X <= 0 { c.X = 0 return 0 } bytes := c.buf.LineBytes(c.Y) tabsize := int(c.buf.Settings["tabsize"].(float64)) return util.StringWidth(bytes, c.X, tabsize) } // GetCharPosInLine gets the char position of a visual x y // coordinate (this is necessary because tabs are 1 char but // 4 visual spaces) func (c *Cursor) GetCharPosInLine(b []byte, visualPos int) int { tabsize := int(c.buf.Settings["tabsize"].(float64)) return util.GetCharPosInLine(b, visualPos, tabsize) } // Start moves the cursor to the start of the line it is on func (c *Cursor) Start() { c.X = 0 c.StoreVisualX() } // StartOfText moves the cursor to the first non-whitespace rune of // the line it is on func (c *Cursor) StartOfText() { c.Start() for util.IsWhitespace(c.RuneUnder(c.X)) { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { break } c.Right() } } // IsStartOfText returns whether the cursor is at the first // non-whitespace rune of the line it is on func (c *Cursor) IsStartOfText() bool { x := 0 for util.IsWhitespace(c.RuneUnder(x)) { if x == util.CharacterCount(c.buf.LineBytes(c.Y)) { break } x++ } return c.X == x } // End moves the cursor to the end of the line it is on func (c *Cursor) End() { c.X = util.CharacterCount(c.buf.LineBytes(c.Y)) c.StoreVisualX() } // CopySelection copies the user's selection to either "primary" // or "clipboard" func (c *Cursor) CopySelection(target clipboard.Register) { if c.HasSelection() { if target != clipboard.PrimaryReg || c.buf.Settings["useprimary"].(bool) { clipboard.WriteMulti(string(c.GetSelection()), target, c.Num, c.buf.NumCursors()) } } } // ResetSelection resets the user's selection func (c *Cursor) ResetSelection() { c.CurSelection[0] = c.buf.Start() c.CurSelection[1] = c.buf.Start() } // SetSelectionStart sets the start of the selection func (c *Cursor) SetSelectionStart(pos Loc) { c.CurSelection[0] = pos } // SetSelectionEnd sets the end of the selection func (c *Cursor) SetSelectionEnd(pos Loc) { c.CurSelection[1] = pos } // HasSelection returns whether or not the user has selected anything func (c *Cursor) HasSelection() bool { return c.CurSelection[0] != c.CurSelection[1] } // DeleteSelection deletes the currently selected text func (c *Cursor) DeleteSelection() { if c.CurSelection[0].GreaterThan(c.CurSelection[1]) { c.buf.Remove(c.CurSelection[1], c.CurSelection[0]) c.Loc = c.CurSelection[1] } else if !c.HasSelection() { return } else { c.buf.Remove(c.CurSelection[0], c.CurSelection[1]) c.Loc = c.CurSelection[0] } } // Deselect closes the cursor's current selection // Start indicates whether the cursor should be placed // at the start or end of the selection func (c *Cursor) Deselect(start bool) { if c.HasSelection() { if start { c.Loc = c.CurSelection[0] } else { c.Loc = c.CurSelection[1] } c.ResetSelection() c.StoreVisualX() } } // GetSelection returns the cursor's selection func (c *Cursor) GetSelection() []byte { if InBounds(c.CurSelection[0], c.buf) && InBounds(c.CurSelection[1], c.buf) { if c.CurSelection[0].GreaterThan(c.CurSelection[1]) { return c.buf.Substr(c.CurSelection[1], c.CurSelection[0]) } return c.buf.Substr(c.CurSelection[0], c.CurSelection[1]) } return []byte{} } // SelectLine selects the current line func (c *Cursor) SelectLine() { c.Start() c.SetSelectionStart(c.Loc) c.End() if len(c.buf.lines)-1 > c.Y { c.SetSelectionEnd(c.Loc.Move(1, c.buf)) } else { c.SetSelectionEnd(c.Loc) } c.OrigSelection = c.CurSelection } // AddLineToSelection adds the current line to the selection func (c *Cursor) AddLineToSelection() { if c.Loc.LessThan(c.OrigSelection[0]) { c.Start() c.SetSelectionStart(c.Loc) c.SetSelectionEnd(c.OrigSelection[1]) } if c.Loc.GreaterThan(c.OrigSelection[1]) { c.End() c.SetSelectionEnd(c.Loc.Move(1, c.buf)) c.SetSelectionStart(c.OrigSelection[0]) } if c.Loc.LessThan(c.OrigSelection[1]) && c.Loc.GreaterThan(c.OrigSelection[0]) { c.CurSelection = c.OrigSelection } } // UpN moves the cursor up N lines (if possible) func (c *Cursor) UpN(amount int) { proposedY := c.Y - amount if proposedY < 0 { proposedY = 0 } else if proposedY >= len(c.buf.lines) { proposedY = len(c.buf.lines) - 1 } bytes := c.buf.LineBytes(proposedY) c.X = c.GetCharPosInLine(bytes, c.LastVisualX) if c.X > util.CharacterCount(bytes) || (amount < 0 && proposedY == c.Y) { c.X = util.CharacterCount(bytes) c.StoreVisualX() } if c.X < 0 || (amount > 0 && proposedY == c.Y) { c.X = 0 c.StoreVisualX() } c.Y = proposedY } // DownN moves the cursor down N lines (if possible) func (c *Cursor) DownN(amount int) { c.UpN(-amount) } // Up moves the cursor up one line (if possible) func (c *Cursor) Up() { c.UpN(1) } // Down moves the cursor down one line (if possible) func (c *Cursor) Down() { c.DownN(1) } // Left moves the cursor left one cell (if possible) or to // the previous line if it is at the beginning func (c *Cursor) Left() { if c.Loc == c.buf.Start() { return } if c.X > 0 { c.X-- } else { c.Up() c.End() } c.StoreVisualX() } // Right moves the cursor right one cell (if possible) or // to the next line if it is at the end func (c *Cursor) Right() { if c.Loc == c.buf.End() { return } if c.X < util.CharacterCount(c.buf.LineBytes(c.Y)) { c.X++ } else { c.Down() c.Start() } c.StoreVisualX() } // Relocate makes sure that the cursor is inside the bounds // of the buffer If it isn't, it moves it to be within the // buffer's lines func (c *Cursor) Relocate() { if c.Y < 0 { c.Y = 0 } else if c.Y >= len(c.buf.lines) { c.Y = len(c.buf.lines) - 1 } if c.X < 0 { c.X = 0 } else if c.X > util.CharacterCount(c.buf.LineBytes(c.Y)) { c.X = util.CharacterCount(c.buf.LineBytes(c.Y)) } } // SelectWord selects the word the cursor is currently on func (c *Cursor) SelectWord() { if len(c.buf.LineBytes(c.Y)) == 0 { return } if !util.IsWordChar(c.RuneUnder(c.X)) { c.SetSelectionStart(c.Loc) c.SetSelectionEnd(c.Loc.Move(1, c.buf)) c.OrigSelection = c.CurSelection return } forward, backward := c.X, c.X for backward > 0 && util.IsWordChar(c.RuneUnder(backward-1)) { backward-- } c.SetSelectionStart(Loc{backward, c.Y}) c.OrigSelection[0] = c.CurSelection[0] lineLen := util.CharacterCount(c.buf.LineBytes(c.Y)) - 1 for forward < lineLen && util.IsWordChar(c.RuneUnder(forward+1)) { forward++ } c.SetSelectionEnd(Loc{forward, c.Y}.Move(1, c.buf)) c.OrigSelection[1] = c.CurSelection[1] c.Loc = c.CurSelection[1] } // AddWordToSelection adds the word the cursor is currently on // to the selection func (c *Cursor) AddWordToSelection() { if c.Loc.GreaterThan(c.OrigSelection[0]) && c.Loc.LessThan(c.OrigSelection[1]) { c.CurSelection = c.OrigSelection return } if c.Loc.LessThan(c.OrigSelection[0]) { backward := c.X for backward > 0 && util.IsWordChar(c.RuneUnder(backward-1)) { backward-- } c.SetSelectionStart(Loc{backward, c.Y}) c.SetSelectionEnd(c.OrigSelection[1]) } if c.Loc.GreaterThan(c.OrigSelection[1]) { forward := c.X lineLen := util.CharacterCount(c.buf.LineBytes(c.Y)) - 1 for forward < lineLen && util.IsWordChar(c.RuneUnder(forward+1)) { forward++ } c.SetSelectionEnd(Loc{forward, c.Y}.Move(1, c.buf)) c.SetSelectionStart(c.OrigSelection[0]) } c.Loc = c.CurSelection[1] } // SelectTo selects from the current cursor location to the given // location func (c *Cursor) SelectTo(loc Loc) { if loc.GreaterThan(c.OrigSelection[0]) { c.SetSelectionStart(c.OrigSelection[0]) c.SetSelectionEnd(loc) } else { c.SetSelectionStart(loc) c.SetSelectionEnd(c.OrigSelection[0]) } } // WordRight moves the cursor one word to the right func (c *Cursor) WordRight() { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { c.Right() return } for util.IsWhitespace(c.RuneUnder(c.X)) { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { return } c.Right() } if util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) && util.IsNonWordChar(c.RuneUnder(c.X+1)) { for util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { return } c.Right() } return } c.Right() for util.IsWordChar(c.RuneUnder(c.X)) { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { return } c.Right() } } // WordLeft moves the cursor one word to the left func (c *Cursor) WordLeft() { if c.X == 0 { c.Left() return } c.Left() for util.IsWhitespace(c.RuneUnder(c.X)) { if c.X == 0 { return } c.Left() } if util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) && util.IsNonWordChar(c.RuneUnder(c.X-1)) { for util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) { if c.X == 0 { return } c.Left() } c.Right() return } c.Left() for util.IsWordChar(c.RuneUnder(c.X)) { if c.X == 0 { return } c.Left() } c.Right() } // SubWordRight moves the cursor one sub-word to the right func (c *Cursor) SubWordRight() { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { c.Right() return } if util.IsWhitespace(c.RuneUnder(c.X)) { for util.IsWhitespace(c.RuneUnder(c.X)) { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { return } c.Right() } return } if util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) { for util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { return } c.Right() } return } if util.IsSubwordDelimiter(c.RuneUnder(c.X)) { for util.IsSubwordDelimiter(c.RuneUnder(c.X)) { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { return } c.Right() } if util.IsWhitespace(c.RuneUnder(c.X)) { return } } if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { return } if util.IsUpperLetter(c.RuneUnder(c.X)) && util.IsUpperLetter(c.RuneUnder(c.X+1)) { for util.IsUpperAlphanumeric(c.RuneUnder(c.X)) { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { return } c.Right() } if util.IsLowerAlphanumeric(c.RuneUnder(c.X)) { c.Left() } } else { c.Right() for util.IsLowerAlphanumeric(c.RuneUnder(c.X)) { if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) { return } c.Right() } } } // SubWordLeft moves the cursor one sub-word to the left func (c *Cursor) SubWordLeft() { if c.X == 0 { c.Left() return } c.Left() if util.IsWhitespace(c.RuneUnder(c.X)) { for util.IsWhitespace(c.RuneUnder(c.X)) { if c.X == 0 { return } c.Left() } c.Right() return } if util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) { for util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) { if c.X == 0 { return } c.Left() } c.Right() return } if util.IsSubwordDelimiter(c.RuneUnder(c.X)) { for util.IsSubwordDelimiter(c.RuneUnder(c.X)) { if c.X == 0 { return } c.Left() } if util.IsWhitespace(c.RuneUnder(c.X)) { c.Right() return } } if c.X == 0 { return } if util.IsUpperLetter(c.RuneUnder(c.X)) && util.IsUpperLetter(c.RuneUnder(c.X-1)) { for util.IsUpperAlphanumeric(c.RuneUnder(c.X)) { if c.X == 0 { return } c.Left() } if !util.IsUpperAlphanumeric(c.RuneUnder(c.X)) { c.Right() } } else { for util.IsLowerAlphanumeric(c.RuneUnder(c.X)) { if c.X == 0 { return } c.Left() } if !util.IsAlphanumeric(c.RuneUnder(c.X)) { c.Right() } } } // RuneUnder returns the rune under the given x position func (c *Cursor) RuneUnder(x int) rune { line := c.buf.LineBytes(c.Y) if len(line) == 0 || x >= util.CharacterCount(line) { return '\n' } else if x < 0 { x = 0 } i := 0 for len(line) > 0 { r, _, size := util.DecodeCharacter(line) line = line[size:] if i == x { return r } i++ } return '\n' } func (c *Cursor) StoreVisualX() { c.LastVisualX = c.GetVisualX(false) c.LastWrappedVisualX = c.GetVisualX(true) } zyedidia-micro-6a62575/internal/buffer/buffer_test.go0000664000175000017510000001513215125206537022171 0ustar nileshnileshpackage buffer import ( "math/rand" "strings" "testing" "github.com/stretchr/testify/assert" lua "github.com/yuin/gopher-lua" "github.com/zyedidia/micro/v2/internal/config" ulua "github.com/zyedidia/micro/v2/internal/lua" "github.com/zyedidia/micro/v2/internal/util" ) type operation struct { start Loc end Loc text []string } func init() { ulua.L = lua.NewState() config.InitRuntimeFiles(false) config.InitGlobalSettings() config.GlobalSettings["backup"] = false config.GlobalSettings["fastdirty"] = true } func check(t *testing.T, before []string, operations []operation, after []string) { assert := assert.New(t) b := NewBufferFromString(strings.Join(before, "\n"), "", BTDefault) assert.NotEqual("", b.GetName()) assert.Equal(false, b.ExternallyModified()) assert.Equal(false, b.Modified()) assert.Equal(1, b.NumCursors()) checkText := func(lines []string) { assert.Equal([]byte(strings.Join(lines, "\n")), b.Bytes()) assert.Equal(len(lines), b.LinesNum()) for i, s := range lines { assert.Equal(s, b.Line(i)) assert.Equal([]byte(s), b.LineBytes(i)) } } checkText(before) var cursors []*Cursor for _, op := range operations { cursor := NewCursor(b, op.start) cursor.SetSelectionStart(op.start) cursor.SetSelectionEnd(op.end) b.AddCursor(cursor) cursors = append(cursors, cursor) } assert.Equal(1+len(operations), b.NumCursors()) for i, op := range operations { cursor := cursors[i] b.SetCurCursor(cursor.Num) cursor.DeleteSelection() b.Insert(cursor.Loc, strings.Join(op.text, "\n")) } checkText(after) // must have exactly two events per operation (delete and insert) for range operations { b.UndoOneEvent() b.UndoOneEvent() } checkText(before) for i, op := range operations { cursor := cursors[i] if op.start == op.end { assert.Equal(op.start, cursor.Loc) } else { assert.Equal(op.start, cursor.CurSelection[0]) assert.Equal(op.end, cursor.CurSelection[1]) } } for range operations { b.RedoOneEvent() b.RedoOneEvent() } checkText(after) b.Close() } const maxLineLength = 200 var alphabet = []rune(" abcdeäم📚") func randomString(length int) string { runes := make([]rune, length) for i := range runes { runes[i] = alphabet[rand.Intn(len(alphabet))] } return string(runes) } func randomText(nLines int) string { lines := make([]string, nLines) for i := range lines { lines[i] = randomString(rand.Intn(maxLineLength + 1)) } return strings.Join(lines, "\n") } func benchCreateAndClose(testingB *testing.B, nLines int) { rand.Seed(int64(nLines)) text := randomText(nLines) testingB.ResetTimer() for i := 0; i < testingB.N; i++ { b := NewBufferFromString(text, "", BTDefault) b.Close() } } func benchRead(testingB *testing.B, nLines int) { rand.Seed(int64(nLines)) b := NewBufferFromString(randomText(nLines), "", BTDefault) testingB.ResetTimer() for i := 0; i < testingB.N; i++ { b.Bytes() for j := 0; j < b.LinesNum(); j++ { b.Line(j) b.LineBytes(j) } } testingB.StopTimer() b.Close() } func benchEdit(testingB *testing.B, nLines, nCursors int) { rand.Seed(int64(nLines + nCursors)) b := NewBufferFromString(randomText(nLines), "", BTDefault) regionSize := nLines / nCursors operations := make([]operation, nCursors) for i := range operations { startLine := (i * regionSize) + rand.Intn(regionSize-5) startColumn := rand.Intn(util.CharacterCountInString(b.Line(startLine)) + 1) endLine := startLine + 1 + rand.Intn(5) endColumn := rand.Intn(util.CharacterCountInString(b.Line(endLine)) + 1) operations[i] = operation{ start: Loc{startColumn, startLine}, end: Loc{endColumn, endLine}, text: []string{randomText(2 + rand.Intn(4))}, } } testingB.ResetTimer() for i := 0; i < testingB.N; i++ { b.SetCursors([]*Cursor{}) var cursors []*Cursor for _, op := range operations { cursor := NewCursor(b, op.start) cursor.SetSelectionStart(op.start) cursor.SetSelectionEnd(op.end) b.AddCursor(cursor) cursors = append(cursors, cursor) } for j, op := range operations { cursor := cursors[j] b.SetCurCursor(cursor.Num) cursor.DeleteSelection() b.Insert(cursor.Loc, op.text[0]) } for b.UndoStack.Peek() != nil { b.UndoOneEvent() } } testingB.StopTimer() b.Close() } func BenchmarkCreateAndClose10Lines(b *testing.B) { benchCreateAndClose(b, 10) } func BenchmarkCreateAndClose100Lines(b *testing.B) { benchCreateAndClose(b, 100) } func BenchmarkCreateAndClose1000Lines(b *testing.B) { benchCreateAndClose(b, 1000) } func BenchmarkCreateAndClose10000Lines(b *testing.B) { benchCreateAndClose(b, 10000) } func BenchmarkCreateAndClose100000Lines(b *testing.B) { benchCreateAndClose(b, 100000) } func BenchmarkCreateAndClose1000000Lines(b *testing.B) { benchCreateAndClose(b, 1000000) } func BenchmarkRead10Lines(b *testing.B) { benchRead(b, 10) } func BenchmarkRead100Lines(b *testing.B) { benchRead(b, 100) } func BenchmarkRead1000Lines(b *testing.B) { benchRead(b, 1000) } func BenchmarkRead10000Lines(b *testing.B) { benchRead(b, 10000) } func BenchmarkRead100000Lines(b *testing.B) { benchRead(b, 100000) } func BenchmarkRead1000000Lines(b *testing.B) { benchRead(b, 1000000) } func BenchmarkEdit10Lines1Cursor(b *testing.B) { benchEdit(b, 10, 1) } func BenchmarkEdit100Lines1Cursor(b *testing.B) { benchEdit(b, 100, 1) } func BenchmarkEdit100Lines10Cursors(b *testing.B) { benchEdit(b, 100, 10) } func BenchmarkEdit1000Lines1Cursor(b *testing.B) { benchEdit(b, 1000, 1) } func BenchmarkEdit1000Lines10Cursors(b *testing.B) { benchEdit(b, 1000, 10) } func BenchmarkEdit1000Lines100Cursors(b *testing.B) { benchEdit(b, 1000, 100) } func BenchmarkEdit10000Lines1Cursor(b *testing.B) { benchEdit(b, 10000, 1) } func BenchmarkEdit10000Lines10Cursors(b *testing.B) { benchEdit(b, 10000, 10) } func BenchmarkEdit10000Lines100Cursors(b *testing.B) { benchEdit(b, 10000, 100) } func BenchmarkEdit10000Lines1000Cursors(b *testing.B) { benchEdit(b, 10000, 1000) } func BenchmarkEdit100000Lines1Cursor(b *testing.B) { benchEdit(b, 100000, 1) } func BenchmarkEdit100000Lines10Cursors(b *testing.B) { benchEdit(b, 100000, 10) } func BenchmarkEdit100000Lines100Cursors(b *testing.B) { benchEdit(b, 100000, 100) } func BenchmarkEdit100000Lines1000Cursors(b *testing.B) { benchEdit(b, 100000, 1000) } func BenchmarkEdit1000000Lines1Cursor(b *testing.B) { benchEdit(b, 1000000, 1) } func BenchmarkEdit1000000Lines10Cursors(b *testing.B) { benchEdit(b, 1000000, 10) } func BenchmarkEdit1000000Lines100Cursors(b *testing.B) { benchEdit(b, 1000000, 100) } func BenchmarkEdit1000000Lines1000Cursors(b *testing.B) { benchEdit(b, 1000000, 1000) } zyedidia-micro-6a62575/internal/buffer/buffer_generated_test.go0000664000175000017510000005437715125206537024225 0ustar nileshnilesh// This file is generated from VSCode model tests by the testgen tool. // DO NOT EDIT THIS FILE BY HAND; your changes will be overwritten! package buffer import "testing" func TestAuto1(t *testing.T) { check( t, []string{ "ioe", "", "yjct", "", "", }, []operation{ { start: Loc{1, 0}, end: Loc{1, 0}, text: []string{ "b", "r", "fq", }, }, { start: Loc{3, 0}, end: Loc{0, 1}, text: []string{ "", "", }, }, }, []string{ "ib", "r", "fqoe", "", "yjct", "", "", }, ) } func TestAuto2(t *testing.T) { check( t, []string{ "f", "littnhskrq", "utxvsizqnk", "lslqz", "jxn", "gmm", }, []operation{ { start: Loc{1, 0}, end: Loc{1, 0}, text: []string{ "", "o", }, }, { start: Loc{3, 1}, end: Loc{3, 1}, text: []string{ "zaq", "avb", }, }, { start: Loc{4, 1}, end: Loc{1, 5}, text: []string{ "jlr", "zl", "j", }, }, }, []string{ "f", "o", "litzaq", "avbtjlr", "zl", "jmm", }, ) } func TestAuto3(t *testing.T) { check( t, []string{ "ofw", "qsxmziuvzw", "rp", "qsnymek", "elth", "wmgzbwudxz", "iwsdkndh", "bujlbwb", "asuouxfv", "xuccnb", }, []operation{ { start: Loc{2, 3}, end: Loc{2, 3}, text: []string{ "", }, }, }, []string{ "ofw", "qsxmziuvzw", "rp", "qsnymek", "elth", "wmgzbwudxz", "iwsdkndh", "bujlbwb", "asuouxfv", "xuccnb", }, ) } func TestAuto4(t *testing.T) { check( t, []string{ "fefymj", "qum", "vmiwxxaiqq", "dz", "lnqdgorosf", }, []operation{ { start: Loc{2, 0}, end: Loc{4, 0}, text: []string{ "hp", }, }, { start: Loc{6, 0}, end: Loc{0, 1}, text: []string{ "kcg", "", "mpx", }, }, { start: Loc{1, 1}, end: Loc{1, 1}, text: []string{ "", "aw", "", }, }, { start: Loc{1, 1}, end: Loc{1, 1}, text: []string{ "vqr", "mo", }, }, { start: Loc{1, 3}, end: Loc{2, 4}, text: []string{ "xyc", }, }, }, []string{ "fehpmjkcg", "", "mpxq", "aw", "vqr", "moum", "vmiwxxaiqq", "dxycqdgorosf", }, ) } func TestBug19872UndoIsFunky(t *testing.T) { check( t, []string{ "something", " A", "", " B", "something else", }, []operation{ { start: Loc{0, 1}, end: Loc{1, 1}, text: []string{ "", }, }, { start: Loc{0, 2}, end: Loc{1, 3}, text: []string{ "", }, }, }, []string{ "something", "A", "B", "something else", }, ) } func TestBug19872UndoIsFunky_2(t *testing.T) { check( t, []string{ "something", "A", "B", "something else", }, []operation{ { start: Loc{0, 1}, end: Loc{0, 1}, text: []string{ " ", }, }, { start: Loc{0, 2}, end: Loc{0, 2}, text: []string{ "", " ", }, }, }, []string{ "something", " A", "", " B", "something else", }, ) } func TestInsertEmptyText(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 0}, text: []string{ "", }, }, }, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestLastOpIsNoOp(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{0, 0}, end: Loc{1, 0}, text: []string{ "", }, }, { start: Loc{0, 3}, end: Loc{0, 3}, text: []string{ "", }, }, }, []string{ "y First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestInsertTextWithoutNewline1(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 0}, text: []string{ "foo ", }, }, }, []string{ "foo My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestInsertTextWithoutNewline2(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{2, 0}, end: Loc{2, 0}, text: []string{ " foo", }, }, }, []string{ "My foo First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestInsertOneNewline(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{3, 0}, end: Loc{3, 0}, text: []string{ "", "", }, }, }, []string{ "My ", "First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestInsertTextWithOneNewline(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{2, 0}, end: Loc{2, 0}, text: []string{ " new line", "No longer", }, }, }, []string{ "My new line", "No longer First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestInsertTextWithTwoNewlines(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{2, 0}, end: Loc{2, 0}, text: []string{ " new line", "One more line in the middle", "No longer", }, }, }, []string{ "My new line", "One more line in the middle", "No longer First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestInsertTextWithManyNewlines(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{2, 0}, end: Loc{2, 0}, text: []string{ "", "", "", "", "", }, }, }, []string{ "My", "", "", "", " First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestInsertMultipleNewlines(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{2, 0}, end: Loc{2, 0}, text: []string{ "", "", "", "", "", }, }, { start: Loc{14, 2}, end: Loc{14, 2}, text: []string{ "a", "b", }, }, }, []string{ "My", "", "", "", " First Line", "\t\tMy Second Line", " Third Linea", "b", "", "1", }, ) } func TestDeleteEmptyText(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 0}, text: []string{ "", }, }, }, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestDeleteTextFromOneLine(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{0, 0}, end: Loc{1, 0}, text: []string{ "", }, }, }, []string{ "y First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestDeleteTextFromOneLine2(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{0, 0}, end: Loc{2, 0}, text: []string{ "a", }, }, }, []string{ "a First Line", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestDeleteAllTextFromALine(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{0, 0}, end: Loc{13, 0}, text: []string{ "", }, }, }, []string{ "", "\t\tMy Second Line", " Third Line", "", "1", }, ) } func TestDeleteTextFromTwoLines(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{3, 0}, end: Loc{5, 1}, text: []string{ "", }, }, }, []string{ "My Second Line", " Third Line", "", "1", }, ) } func TestDeleteTextFromManyLines(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{3, 0}, end: Loc{4, 2}, text: []string{ "", }, }, }, []string{ "My Third Line", "", "1", }, ) } func TestDeleteEverything(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "1", }, []operation{ { start: Loc{0, 0}, end: Loc{1, 4}, text: []string{ "", }, }, }, []string{ "", }, ) } func TestTwoUnrelatedEdits(t *testing.T) { check( t, []string{ "My First Line", "\t\tMy Second Line", " Third Line", "", "123", }, []operation{ { start: Loc{0, 1}, end: Loc{2, 1}, text: []string{ "\t", }, }, { start: Loc{0, 2}, end: Loc{4, 2}, text: []string{ "", }, }, }, []string{ "My First Line", "\tMy Second Line", "Third Line", "", "123", }, ) } func TestTwoEditsOnOneLine(t *testing.T) { check( t, []string{ "\t\tfirst\t ", "\t\tsecond line", "\tthird line", "fourth line", "\t\t\t\t", }, []operation{ { start: Loc{2, 4}, end: Loc{6, 4}, text: []string{ "", }, }, { start: Loc{11, 4}, end: Loc{15, 4}, text: []string{ "", }, }, }, []string{ "\t\tfirst\t ", "\t\tsecond line", "\tthird line", "fourth line", "\t\tfifth\t\t", }, ) } func TestManyEdits(t *testing.T) { check( t, []string{ "{\"x\" : 1}", }, []operation{ { start: Loc{1, 0}, end: Loc{1, 0}, text: []string{ "\n ", }, }, { start: Loc{4, 0}, end: Loc{5, 0}, text: []string{ "", }, }, { start: Loc{8, 0}, end: Loc{8, 0}, text: []string{ "\n", }, }, }, []string{ "{", " \"x\": 1", "}", }, ) } func TestManyEditsReversed(t *testing.T) { check( t, []string{ "{", " \"x\": 1", "}", }, []operation{ { start: Loc{1, 0}, end: Loc{2, 1}, text: []string{ "", }, }, { start: Loc{5, 1}, end: Loc{5, 1}, text: []string{ " ", }, }, { start: Loc{8, 1}, end: Loc{0, 2}, text: []string{ "", }, }, }, []string{ "{\"x\" : 1}", }, ) } func TestReplacingNewlines1(t *testing.T) { check( t, []string{ "{", "\"a\": true,", "", "\"b\": true", "}", }, []operation{ { start: Loc{1, 0}, end: Loc{0, 1}, text: []string{ "", "\t", }, }, { start: Loc{10, 1}, end: Loc{0, 3}, text: []string{ "", "\t", }, }, }, []string{ "{", "\t\"a\": true,", "\t\"b\": true", "}", }, ) } func TestReplacingNewlines2(t *testing.T) { check( t, []string{ "some text", "some more text", "now comes an empty line", "", "after empty line", "and the last line", }, []operation{ { start: Loc{4, 0}, end: Loc{0, 2}, text: []string{ " text", "some more text", "some more text", }, }, { start: Loc{1, 2}, end: Loc{0, 3}, text: []string{ "o more lines", "asd", "asd", "asd", }, }, { start: Loc{0, 4}, end: Loc{5, 4}, text: []string{ "zzzzzzzz", }, }, { start: Loc{10, 4}, end: Loc{15, 5}, text: []string{ "1", "2", "3", "4", }, }, }, []string{ "some text", "some more text", "some more textno more lines", "asd", "asd", "asd", "zzzzzzzz empt1", "2", "3", "4ne", }, ) } func TestAdvanced1(t *testing.T) { check( t, []string{ " { \"d\": [", " null", " ] /*comment*/", " ,\"e\": /*comment*/ [null] }", }, []operation{ { start: Loc{0, 0}, end: Loc{1, 0}, text: []string{ "", }, }, { start: Loc{2, 0}, end: Loc{9, 0}, text: []string{ "", " ", }, }, { start: Loc{15, 0}, end: Loc{13, 1}, text: []string{ "", " ", }, }, { start: Loc{17, 1}, end: Loc{8, 2}, text: []string{ "", " ", }, }, { start: Loc{21, 2}, end: Loc{8, 3}, text: []string{ "", }, }, { start: Loc{9, 3}, end: Loc{9, 3}, text: []string{ "", " ", }, }, { start: Loc{27, 3}, end: Loc{27, 3}, text: []string{ "", " ", }, }, { start: Loc{31, 3}, end: Loc{31, 3}, text: []string{ "", " ", }, }, { start: Loc{32, 3}, end: Loc{33, 3}, text: []string{ "", "", }, }, }, []string{ "{", " \"d\": [", " null", " ] /*comment*/,", " \"e\": /*comment*/ [", " null", " ]", "}", }, ) } func TestAdvancedSimplified(t *testing.T) { check( t, []string{ " abc", " ,def", }, []operation{ { start: Loc{0, 0}, end: Loc{3, 0}, text: []string{ "", }, }, { start: Loc{6, 0}, end: Loc{1, 1}, text: []string{ "", }, }, { start: Loc{2, 1}, end: Loc{2, 1}, text: []string{ "", "", }, }, }, []string{ "abc,", "def", }, ) } func TestIssue144(t *testing.T) { check( t, []string{ "package caddy", "", "func main() {", "\tfmt.Println(\"Hello World! :)\")", "}", "", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 5}, text: []string{ "package caddy", "", "import \"fmt\"", "", "func main() {", "\tfmt.Println(\"Hello World! :)\")", "}", "", }, }, }, []string{ "package caddy", "", "import \"fmt\"", "", "func main() {", "\tfmt.Println(\"Hello World! :)\")", "}", "", }, ) } func TestIssue2586ReplacingSelectedEndOfLineWithNewlineLocksUpTheDocument(t *testing.T) { check( t, []string{ "something", "interesting", }, []operation{ { start: Loc{9, 0}, end: Loc{0, 1}, text: []string{ "", "", }, }, }, []string{ "something", "interesting", }, ) } func TestIssue3980(t *testing.T) { check( t, []string{ "class A {", " someProperty = false;", " someMethod() {", " this.someMethod();", " }", "}", }, []operation{ { start: Loc{7, 0}, end: Loc{8, 0}, text: []string{ "", "", }, }, { start: Loc{16, 2}, end: Loc{17, 2}, text: []string{ "", "", }, }, { start: Loc{17, 2}, end: Loc{17, 2}, text: []string{ " ", }, }, { start: Loc{4, 3}, end: Loc{4, 3}, text: []string{ " ", }, }, }, []string{ "class A", "{", " someProperty = false;", " someMethod()", " {", " this.someMethod();", " }", "}", }, ) } func TestTouchingEditsTwoInsertsAtTheSamePosition(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 0}, text: []string{ "a", }, }, { start: Loc{0, 0}, end: Loc{0, 0}, text: []string{ "b", }, }, }, []string{ "abhello world", }, ) } func TestTouchingEditsInsertAndReplaceTouching(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 0}, text: []string{ "b", }, }, { start: Loc{0, 0}, end: Loc{2, 0}, text: []string{ "ab", }, }, }, []string{ "babllo world", }, ) } func TestTouchingEditsTwoTouchingReplaces(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{1, 0}, text: []string{ "H", }, }, { start: Loc{1, 0}, end: Loc{2, 0}, text: []string{ "E", }, }, }, []string{ "HEllo world", }, ) } func TestTouchingEditsTwoTouchingDeletes(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{1, 0}, text: []string{ "", }, }, { start: Loc{1, 0}, end: Loc{2, 0}, text: []string{ "", }, }, }, []string{ "llo world", }, ) } func TestTouchingEditsInsertAndReplace(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 0}, text: []string{ "H", }, }, { start: Loc{0, 0}, end: Loc{2, 0}, text: []string{ "e", }, }, }, []string{ "Hello world", }, ) } func TestTouchingEditsReplaceAndInsert(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{2, 0}, text: []string{ "H", }, }, { start: Loc{2, 0}, end: Loc{2, 0}, text: []string{ "e", }, }, }, []string{ "Hello world", }, ) } func TestSingleDelete1(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{1, 0}, text: []string{ "", }, }, }, []string{ "ello world", }, ) } func TestSingleDelete2(t *testing.T) { check( t, []string{ "helloworld", }, []operation{ { start: Loc{2, 0}, end: Loc{7, 0}, text: []string{ "", }, }, }, []string{ "herld", }, ) } func TestSingleDelete3(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{5, 0}, text: []string{ "", }, }, }, []string{ " world", }, ) } func TestSingleDelete4(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{1, 0}, end: Loc{6, 0}, text: []string{ "", }, }, }, []string{ "hworld", }, ) } func TestSingleDelete5(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{11, 0}, text: []string{ "", }, }, }, []string{ "", }, ) } func TestMultiDelete6(t *testing.T) { check( t, []string{ "hello world", "hello world", "hello world", }, []operation{ { start: Loc{5, 0}, end: Loc{5, 2}, text: []string{ "", }, }, }, []string{ "hello world", }, ) } func TestMultiDelete7(t *testing.T) { check( t, []string{ "hello world", "hello world", "hello world", }, []operation{ { start: Loc{11, 0}, end: Loc{11, 2}, text: []string{ "", }, }, }, []string{ "hello world", }, ) } func TestMultiDelete8(t *testing.T) { check( t, []string{ "hello world", "hello world", "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 2}, text: []string{ "", }, }, }, []string{ "hello world", }, ) } func TestMultiDelete9(t *testing.T) { check( t, []string{ "hello world", "hello world", "hello world", }, []operation{ { start: Loc{11, 0}, end: Loc{0, 2}, text: []string{ "", }, }, }, []string{ "hello worldhello world", }, ) } func TestSingleInsert1(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 0}, text: []string{ "xx", }, }, }, []string{ "xxhello world", }, ) } func TestSingleInsert2(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{1, 0}, end: Loc{1, 0}, text: []string{ "xx", }, }, }, []string{ "hxxello world", }, ) } func TestSingleInsert3(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{5, 0}, end: Loc{5, 0}, text: []string{ "xx", }, }, }, []string{ "helloxx world", }, ) } func TestSingleInsert4(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{6, 0}, end: Loc{6, 0}, text: []string{ "xx", }, }, }, []string{ "hello xxworld", }, ) } func TestSingleInsert5(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{11, 0}, end: Loc{11, 0}, text: []string{ "xx", }, }, }, []string{ "hello worldxx", }, ) } func TestMultiInsert6(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{0, 0}, end: Loc{0, 0}, text: []string{ "\n", }, }, }, []string{ "", "hello world", }, ) } func TestMultiInsert7(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{11, 0}, end: Loc{11, 0}, text: []string{ "\n", }, }, }, []string{ "hello world", "", }, ) } func TestMultiInsert8(t *testing.T) { check( t, []string{ "hello world", }, []operation{ { start: Loc{6, 0}, end: Loc{6, 0}, text: []string{ "\n", }, }, }, []string{ "hello ", "world", }, ) } func TestMultiInsert9(t *testing.T) { check( t, []string{ "hello world", "hello world", }, []operation{ { start: Loc{6, 0}, end: Loc{6, 0}, text: []string{ "xx\nyy", }, }, }, []string{ "hello xx", "yyworld", "hello world", }, ) } zyedidia-micro-6a62575/internal/buffer/buffer.go0000664000175000017510000011056315125206537021136 0ustar nileshnileshpackage buffer import ( "bufio" "bytes" "crypto/md5" "errors" "fmt" "io" "io/fs" "os" "path/filepath" "strconv" "strings" "sync" "time" luar "layeh.com/gopher-luar" dmp "github.com/sergi/go-diff/diffmatchpatch" "github.com/zyedidia/micro/v2/internal/config" ulua "github.com/zyedidia/micro/v2/internal/lua" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" "github.com/zyedidia/micro/v2/pkg/highlight" "golang.org/x/text/encoding" "golang.org/x/text/encoding/htmlindex" "golang.org/x/text/encoding/unicode" "golang.org/x/text/transform" ) var ( // OpenBuffers is a list of the currently open buffers OpenBuffers []*Buffer // LogBuf is a reference to the log buffer which can be opened with the // `> log` command LogBuf *Buffer ) // The BufType defines what kind of buffer this is type BufType struct { Kind int Readonly bool // The buffer cannot be edited Scratch bool // The buffer cannot be saved Syntax bool // Syntax highlighting is enabled } var ( // BTDefault is a default buffer BTDefault = BufType{0, false, false, true} // BTHelp is a help buffer BTHelp = BufType{1, true, true, true} // BTLog is a log buffer BTLog = BufType{2, true, true, false} // BTScratch is a buffer that cannot be saved (for scratch work) BTScratch = BufType{3, false, true, false} // BTRaw is a buffer that shows raw terminal events BTRaw = BufType{4, false, true, false} // BTInfo is a buffer for inputting information BTInfo = BufType{5, false, true, false} // BTStdout is a buffer that only writes to stdout // when closed BTStdout = BufType{6, false, true, true} ) // SharedBuffer is a struct containing info that is shared among buffers // that have the same file open type SharedBuffer struct { *LineArray // Stores the last modification time of the file the buffer is pointing to ModTime time.Time // Type of the buffer (e.g. help, raw, scratch etc..) Type BufType // Path to the file on disk Path string // Absolute path to the file on disk AbsPath string // Name of the buffer on the status line name string toStdout bool // Settings customized by the user Settings map[string]any // LocalSettings customized by the user for this buffer only LocalSettings map[string]bool encoding encoding.Encoding Suggestions []string Completions []string CurSuggestion int Messages []*Message updateDiffTimer *time.Timer diffBase []byte diffBaseLineCount int diffLock sync.RWMutex diff map[int]DiffStatus forceKeepBackup bool // ReloadDisabled allows the user to disable reloads if they // are viewing a file that is constantly changing ReloadDisabled bool isModified bool // Whether or not suggestions can be autocompleted must be shared because // it changes based on how the buffer has changed HasSuggestions bool // The Highlighter struct actually performs the highlighting Highlighter *highlight.Highlighter // SyntaxDef represents the syntax highlighting definition being used // This stores the highlighting rules and filetype detection info SyntaxDef *highlight.Def ModifiedThisFrame bool // Hash of the original buffer -- empty if fastdirty is on origHash [md5.Size]byte } func (b *SharedBuffer) insert(pos Loc, value []byte) { b.HasSuggestions = false b.LineArray.insert(pos, value) b.setModified() inslines := bytes.Count(value, []byte{'\n'}) b.MarkModified(pos.Y, pos.Y+inslines) } func (b *SharedBuffer) remove(start, end Loc) []byte { b.HasSuggestions = false defer b.setModified() defer b.MarkModified(start.Y, end.Y) return b.LineArray.remove(start, end) } func (b *SharedBuffer) setModified() { if b.Type.Scratch { return } if b.Settings["fastdirty"].(bool) { b.isModified = true } else { var buff [md5.Size]byte b.calcHash(&buff) b.isModified = buff != b.origHash } if b.isModified { b.RequestBackup() } else { b.CancelBackup() } } // calcHash calculates md5 hash of all lines in the buffer func (b *SharedBuffer) calcHash(out *[md5.Size]byte) { h := md5.New() if len(b.lines) > 0 { h.Write(b.lines[0].data) for _, l := range b.lines[1:] { if b.Endings == FFDos { h.Write([]byte{'\r', '\n'}) } else { h.Write([]byte{'\n'}) } h.Write(l.data) } } h.Sum((*out)[:0]) } // MarkModified marks the buffer as modified for this frame // and performs rehighlighting if syntax highlighting is enabled func (b *SharedBuffer) MarkModified(start, end int) { b.ModifiedThisFrame = true start = util.Clamp(start, 0, len(b.lines)-1) end = util.Clamp(end, 0, len(b.lines)-1) if b.Settings["syntax"].(bool) && b.SyntaxDef != nil { l := -1 for i := start; i <= end; i++ { l = util.Max(b.Highlighter.ReHighlightStates(b, i), l) } b.Highlighter.HighlightMatches(b, start, l) } for i := start; i <= end; i++ { b.LineArray.invalidateSearchMatches(i) } } // DisableReload disables future reloads of this sharedbuffer func (b *SharedBuffer) DisableReload() { b.ReloadDisabled = true } const ( DSUnchanged = 0 DSAdded = 1 DSModified = 2 DSDeletedAbove = 3 ) type DiffStatus byte type Command struct { StartCursor Loc SearchRegex string SearchAfterStart bool } var emptyCommand = Command{ StartCursor: Loc{-1, -1}, SearchRegex: "", SearchAfterStart: false, } // Buffer stores the main information about a currently open file including // the actual text (in a LineArray), the undo/redo stack (in an EventHandler) // all the cursors, the syntax highlighting info, the settings for the buffer // and some misc info about modification time and path location. // The syntax highlighting info must be stored with the buffer because the syntax // highlighter attaches information to each line of the buffer for optimization // purposes so it doesn't have to rehighlight everything on every update. // Likewise for the search highlighting. type Buffer struct { *EventHandler *SharedBuffer cursors []*Cursor curCursor int StartCursor Loc // OptionCallback is called after a buffer option value is changed. // The display module registers its OptionCallback to ensure the buffer window // is properly updated when needed. This is a workaround for the fact that // the buffer module cannot directly call the display's API (it would mean // a circular dependency between packages). OptionCallback func(option string, nativeValue any) // The display module registers its own GetVisualX function for getting // the correct visual x location of a cursor when softwrap is used. // This is hacky. Maybe it would be better to move all the visual x logic // from buffer to display, but it would require rewriting a lot of code. GetVisualX func(loc Loc) int // Last search stores the last successful search LastSearch string LastSearchRegex bool // HighlightSearch enables highlighting all instances of the last successful search HighlightSearch bool // OverwriteMode indicates that we are in overwrite mode (toggled by // Insert key by default) i.e. that typing a character shall replace the // character under the cursor instead of inserting a character before it. OverwriteMode bool } // NewBufferFromFileWithCommand opens a new buffer with a given command // If cmd.StartCursor is {-1, -1} the location does not overwrite what the cursor location // would otherwise be (start of file, or saved cursor position if `savecursor` is // enabled) func NewBufferFromFileWithCommand(path string, btype BufType, cmd Command) (*Buffer, error) { var err error filename := path if config.GetGlobalOption("parsecursor").(bool) && cmd.StartCursor.X == -1 && cmd.StartCursor.Y == -1 { var cursorPos []string filename, cursorPos = util.GetPathAndCursorPosition(filename) cmd.StartCursor, err = ParseCursorLocation(cursorPos) if err != nil { cmd.StartCursor = Loc{-1, -1} } } filename, err = util.ReplaceHome(filename) if err != nil { return nil, err } fileInfo, serr := os.Stat(filename) if serr != nil && !errors.Is(serr, fs.ErrNotExist) { return nil, serr } if serr == nil && fileInfo.IsDir() { return nil, errors.New("Error: " + filename + " is a directory and cannot be opened") } if serr == nil && !fileInfo.Mode().IsRegular() { return nil, errors.New("Error: " + filename + " is not a regular file and cannot be opened") } f, err := os.OpenFile(filename, os.O_WRONLY, 0) readonly := errors.Is(err, fs.ErrPermission) f.Close() file, err := os.Open(filename) if err == nil { defer file.Close() } var buf *Buffer if errors.Is(err, fs.ErrNotExist) { // File does not exist -- create an empty buffer with that name buf = NewBufferFromString("", filename, btype) } else if err != nil { return nil, err } else { buf = NewBuffer(file, util.FSize(file), filename, btype, cmd) if buf == nil { return nil, errors.New("could not open file") } } if readonly && prompt != nil { prompt.Message(fmt.Sprintf("Warning: file is readonly - %s will be attempted when saving", config.GlobalSettings["sucmd"].(string))) // buf.SetOptionNative("readonly", true) } return buf, nil } // NewBufferFromFile opens a new buffer using the given path // It will also automatically handle `~`, and line/column with filename:l:c // It will return an empty buffer if the path does not exist // and an error if the file is a directory func NewBufferFromFile(path string, btype BufType) (*Buffer, error) { return NewBufferFromFileWithCommand(path, btype, emptyCommand) } // NewBufferFromStringWithCommand creates a new buffer containing the given string // with a cursor loc and a search text func NewBufferFromStringWithCommand(text, path string, btype BufType, cmd Command) *Buffer { return NewBuffer(strings.NewReader(text), int64(len(text)), path, btype, cmd) } // NewBufferFromString creates a new buffer containing the given string func NewBufferFromString(text, path string, btype BufType) *Buffer { return NewBuffer(strings.NewReader(text), int64(len(text)), path, btype, emptyCommand) } // NewBuffer creates a new buffer from a given reader with a given path // Ensure that ReadSettings and InitGlobalSettings have been called before creating // a new buffer // Places the cursor at startcursor. If startcursor is -1, -1 places the // cursor at an autodetected location (based on savecursor or :LINE:COL) func NewBuffer(r io.Reader, size int64, path string, btype BufType, cmd Command) *Buffer { absPath, err := filepath.Abs(path) if err != nil { absPath = path } b := new(Buffer) found := false if len(path) > 0 { for _, buf := range OpenBuffers { if buf.AbsPath == absPath && buf.Type != BTInfo { found = true b.SharedBuffer = buf.SharedBuffer b.EventHandler = buf.EventHandler } } } hasBackup := false if !found { b.SharedBuffer = new(SharedBuffer) b.Type = btype b.AbsPath = absPath b.Path = path b.Settings = config.DefaultCommonSettings() b.LocalSettings = make(map[string]bool) for k, v := range config.GlobalSettings { if _, ok := config.DefaultGlobalOnlySettings[k]; !ok { // make sure setting is not global-only b.Settings[k] = v } } config.UpdatePathGlobLocals(b.Settings, absPath) b.encoding, err = htmlindex.Get(b.Settings["encoding"].(string)) if err != nil { b.encoding = unicode.UTF8 b.Settings["encoding"] = "utf-8" } var ok bool hasBackup, ok = b.ApplyBackup(size) if !ok { return NewBufferFromString("", "", btype) } if !hasBackup { reader := bufio.NewReader(transform.NewReader(r, b.encoding.NewDecoder())) var ff FileFormat = FFAuto if size == 0 { // for empty files, use the fileformat setting instead of // autodetection switch b.Settings["fileformat"] { case "unix": ff = FFUnix case "dos": ff = FFDos } } else { // in case of autodetection treat as locally set b.LocalSettings["fileformat"] = true } b.LineArray = NewLineArray(uint64(size), ff, reader) } b.EventHandler = NewEventHandler(b.SharedBuffer, b.cursors) // The last time this file was modified b.UpdateModTime() } if b.Settings["readonly"].(bool) && b.Type == BTDefault { b.Type.Readonly = true } switch b.Endings { case FFUnix: b.Settings["fileformat"] = "unix" case FFDos: b.Settings["fileformat"] = "dos" } b.UpdateRules() // we know the filetype now, so update per-filetype settings config.UpdateFileTypeLocals(b.Settings, b.Settings["filetype"].(string)) if _, err := os.Stat(filepath.Join(config.ConfigDir, "buffers")); errors.Is(err, fs.ErrNotExist) { os.Mkdir(filepath.Join(config.ConfigDir, "buffers"), os.ModePerm) } if cmd.StartCursor.X != -1 && cmd.StartCursor.Y != -1 { b.StartCursor = cmd.StartCursor } else if b.Settings["savecursor"].(bool) || b.Settings["saveundo"].(bool) { err := b.Unserialize() if err != nil { screen.TermMessage(err) } } b.AddCursor(NewCursor(b, b.StartCursor)) b.GetActiveCursor().Relocate() if cmd.SearchRegex != "" { match, found, _ := b.FindNext(cmd.SearchRegex, b.Start(), b.End(), b.StartCursor, true, true) if found { if cmd.SearchAfterStart { // Search from current cursor and move it accordingly b.GetActiveCursor().SetSelectionStart(match[0]) b.GetActiveCursor().SetSelectionEnd(match[1]) b.GetActiveCursor().OrigSelection[0] = b.GetActiveCursor().CurSelection[0] b.GetActiveCursor().OrigSelection[1] = b.GetActiveCursor().CurSelection[1] b.GetActiveCursor().GotoLoc(match[1]) } b.LastSearch = cmd.SearchRegex b.LastSearchRegex = true b.HighlightSearch = b.Settings["hlsearch"].(bool) } } if !b.Settings["fastdirty"].(bool) && !found { if size > LargeFileThreshold { // If the file is larger than LargeFileThreshold fastdirty needs to be on b.Settings["fastdirty"] = true } else if !hasBackup { // since applying a backup does not save the applied backup to disk, we should // not calculate the original hash based on the backup data b.calcHash(&b.origHash) } } err = config.RunPluginFn("onBufferOpen", luar.New(ulua.L, b)) if err != nil { screen.TermMessage(err) } OpenBuffers = append(OpenBuffers, b) return b } // CloseOpenBuffers removes all open buffers func CloseOpenBuffers() { for i, buf := range OpenBuffers { buf.Fini() OpenBuffers[i] = nil } OpenBuffers = OpenBuffers[:0] } // Close removes this buffer from the list of open buffers func (b *Buffer) Close() { for i, buf := range OpenBuffers { if b == buf { b.Fini() copy(OpenBuffers[i:], OpenBuffers[i+1:]) OpenBuffers[len(OpenBuffers)-1] = nil OpenBuffers = OpenBuffers[:len(OpenBuffers)-1] return } } } // Fini should be called when a buffer is closed and performs // some cleanup func (b *Buffer) Fini() { if !b.Modified() { b.Serialize() } b.CancelBackup() if b.Type == BTStdout { fmt.Fprint(util.Stdout, string(b.Bytes())) } } // GetName returns the name that should be displayed in the statusline // for this buffer func (b *Buffer) GetName() string { name := b.name if name == "" { if b.Path == "" { return "No name" } name = b.Path } if b.Settings["basename"].(bool) { return filepath.Base(name) } return name } // SetName changes the name for this buffer func (b *Buffer) SetName(s string) { b.name = s } // Insert inserts the given string of text at the start location func (b *Buffer) Insert(start Loc, text string) { if !b.Type.Readonly { b.EventHandler.cursors = b.cursors b.EventHandler.active = b.curCursor b.EventHandler.Insert(start, text) } } // Remove removes the characters between the start and end locations func (b *Buffer) Remove(start, end Loc) { if !b.Type.Readonly { b.EventHandler.cursors = b.cursors b.EventHandler.active = b.curCursor b.EventHandler.Remove(start, end) } } // FileType returns the buffer's filetype func (b *Buffer) FileType() string { return b.Settings["filetype"].(string) } // ExternallyModified returns whether the file being edited has // been modified by some external process func (b *Buffer) ExternallyModified() bool { modTime, err := util.GetModTime(b.Path) if err == nil { return modTime != b.ModTime } return false } // UpdateModTime updates the modtime of this file func (b *Buffer) UpdateModTime() (err error) { b.ModTime, err = util.GetModTime(b.Path) return } // ReOpen reloads the current buffer from disk func (b *Buffer) ReOpen() error { file, err := os.Open(b.Path) if err != nil { return err } defer file.Close() enc, err := htmlindex.Get(b.Settings["encoding"].(string)) if err != nil { return err } reader := bufio.NewReader(transform.NewReader(file, enc.NewDecoder())) data, err := io.ReadAll(reader) txt := string(data) if err != nil { return err } b.EventHandler.ApplyDiff(txt) err = b.UpdateModTime() if !b.Settings["fastdirty"].(bool) { if len(data) > LargeFileThreshold { b.Settings["fastdirty"] = true } else { b.calcHash(&b.origHash) } } b.isModified = false b.RelocateCursors() return err } // RelocateCursors relocates all cursors (makes sure they are in the buffer) func (b *Buffer) RelocateCursors() { for _, c := range b.cursors { c.Relocate() } } // DeselectCursors removes selection from all cursors func (b *Buffer) DeselectCursors() { for _, c := range b.cursors { c.Deselect(true) } } // RuneAt returns the rune at a given location in the buffer func (b *Buffer) RuneAt(loc Loc) rune { line := b.LineBytes(loc.Y) if len(line) > 0 { i := 0 for len(line) > 0 { r, _, size := util.DecodeCharacter(line) line = line[size:] if i == loc.X { return r } i++ } } return '\n' } // WordAt returns the word around a given location in the buffer func (b *Buffer) WordAt(loc Loc) []byte { if len(b.LineBytes(loc.Y)) == 0 || !util.IsWordChar(b.RuneAt(loc)) { return []byte{} } start := loc end := loc.Move(1, b) for start.X > 0 && util.IsWordChar(b.RuneAt(start.Move(-1, b))) { start.X-- } lineLen := util.CharacterCount(b.LineBytes(loc.Y)) for end.X < lineLen && util.IsWordChar(b.RuneAt(end)) { end.X++ } return b.Substr(start, end) } // Shared returns if there are other buffers with the same file as this buffer func (b *Buffer) Shared() bool { for _, buf := range OpenBuffers { if buf != b && buf.SharedBuffer == b.SharedBuffer { return true } } return false } // Modified returns if this buffer has been modified since // being opened func (b *Buffer) Modified() bool { return b.isModified } // Size returns the number of bytes in the current buffer func (b *Buffer) Size() int { nb := 0 for i := 0; i < b.LinesNum(); i++ { nb += len(b.LineBytes(i)) if i != b.LinesNum()-1 { if b.Endings == FFDos { nb++ // carriage return } nb++ // newline } } return nb } func parseDefFromFile(f config.RuntimeFile, header *highlight.Header) *highlight.Def { data, err := f.Data() if err != nil { screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error()) return nil } if header == nil { header, err = highlight.MakeHeaderYaml(data) if err != nil { screen.TermMessage("Error parsing header for syntax file " + f.Name() + ": " + err.Error()) return nil } } file, err := highlight.ParseFile(data) if err != nil { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) return nil } syndef, err := highlight.ParseDef(file, header) if err != nil { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) return nil } return syndef } // findRealRuntimeSyntaxDef finds a specific syntax definition // in the user's custom syntax files func findRealRuntimeSyntaxDef(name string, header *highlight.Header) *highlight.Def { for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) { if f.Name() == name { syndef := parseDefFromFile(f, header) if syndef != nil { return syndef } } } return nil } // findRuntimeSyntaxDef finds a specific syntax definition // in the built-in syntax files func findRuntimeSyntaxDef(name string, header *highlight.Header) *highlight.Def { for _, f := range config.ListRuntimeFiles(config.RTSyntax) { if f.Name() == name { syndef := parseDefFromFile(f, header) if syndef != nil { return syndef } } } return nil } func resolveIncludes(syndef *highlight.Def) { includes := highlight.GetIncludes(syndef) if len(includes) == 0 { return } var files []*highlight.File for _, f := range config.ListRuntimeFiles(config.RTSyntax) { data, err := f.Data() if err != nil { screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error()) continue } header, err := highlight.MakeHeaderYaml(data) if err != nil { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) continue } for _, i := range includes { if header.FileType == i { file, err := highlight.ParseFile(data) if err != nil { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) continue } files = append(files, file) break } } if len(files) >= len(includes) { break } } highlight.ResolveIncludes(syndef, files) } // UpdateRules updates the syntax rules and filetype for this buffer // This is called when the colorscheme changes func (b *Buffer) UpdateRules() { if !b.Type.Syntax { return } ft := b.Settings["filetype"].(string) if ft == "off" { b.ClearMatches() b.SyntaxDef = nil return } b.SyntaxDef = nil // syntaxFileInfo is an internal helper structure // to store properties of one single syntax file type syntaxFileInfo struct { header *highlight.Header fileName string syntaxDef *highlight.Def } fnameMatches := []syntaxFileInfo{} headerMatches := []syntaxFileInfo{} syntaxFile := "" foundDef := false var header *highlight.Header // search for the syntax file in the user's custom syntax files for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) { if f.Name() == "default" { continue } data, err := f.Data() if err != nil { screen.TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error()) continue } header, err = highlight.MakeHeaderYaml(data) if err != nil { screen.TermMessage("Error parsing header for syntax file " + f.Name() + ": " + err.Error()) continue } matchedFileType := false matchedFileName := false matchedFileHeader := false if ft == "unknown" || ft == "" { if header.MatchFileName(b.Path) { matchedFileName = true } if len(fnameMatches) == 0 && header.MatchFileHeader(b.lines[0].data) { matchedFileHeader = true } } else if header.FileType == ft { matchedFileType = true } if matchedFileType || matchedFileName || matchedFileHeader { file, err := highlight.ParseFile(data) if err != nil { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) continue } syndef, err := highlight.ParseDef(file, header) if err != nil { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) continue } if matchedFileType { b.SyntaxDef = syndef syntaxFile = f.Name() foundDef = true break } if matchedFileName { fnameMatches = append(fnameMatches, syntaxFileInfo{header, f.Name(), syndef}) } else if matchedFileHeader { headerMatches = append(headerMatches, syntaxFileInfo{header, f.Name(), syndef}) } } } if !foundDef { // search for the syntax file in the built-in syntax files for _, f := range config.ListRuntimeFiles(config.RTSyntaxHeader) { data, err := f.Data() if err != nil { screen.TermMessage("Error loading syntax header file " + f.Name() + ": " + err.Error()) continue } header, err = highlight.MakeHeader(data) if err != nil { screen.TermMessage("Error reading syntax header file", f.Name(), err) continue } if ft == "unknown" || ft == "" { if header.MatchFileName(b.Path) { fnameMatches = append(fnameMatches, syntaxFileInfo{header, f.Name(), nil}) } if len(fnameMatches) == 0 && header.MatchFileHeader(b.lines[0].data) { headerMatches = append(headerMatches, syntaxFileInfo{header, f.Name(), nil}) } } else if header.FileType == ft { syntaxFile = f.Name() break } } } if syntaxFile == "" { matches := fnameMatches if len(matches) == 0 { matches = headerMatches } length := len(matches) if length > 0 { signatureMatch := false if length > 1 { // multiple matching syntax files found, try to resolve the ambiguity // using signatures detectlimit := util.IntOpt(b.Settings["detectlimit"]) lineCount := len(b.lines) limit := lineCount if detectlimit > 0 && lineCount > detectlimit { limit = detectlimit } matchLoop: for _, m := range matches { if m.header.HasFileSignature() { for i := 0; i < limit; i++ { if m.header.MatchFileSignature(b.lines[i].data) { syntaxFile = m.fileName if m.syntaxDef != nil { b.SyntaxDef = m.syntaxDef foundDef = true } header = m.header signatureMatch = true break matchLoop } } } } } if length == 1 || !signatureMatch { syntaxFile = matches[0].fileName if matches[0].syntaxDef != nil { b.SyntaxDef = matches[0].syntaxDef foundDef = true } header = matches[0].header } } } if syntaxFile != "" && !foundDef { // we found a syntax file using a syntax header file b.SyntaxDef = findRuntimeSyntaxDef(syntaxFile, header) } if b.SyntaxDef != nil { b.Settings["filetype"] = b.SyntaxDef.FileType } else { // search for the default file in the user's custom syntax files b.SyntaxDef = findRealRuntimeSyntaxDef("default", nil) if b.SyntaxDef == nil { // search for the default file in the built-in syntax files b.SyntaxDef = findRuntimeSyntaxDef("default", nil) } } if b.SyntaxDef != nil { resolveIncludes(b.SyntaxDef) } if b.SyntaxDef != nil { b.Highlighter = highlight.NewHighlighter(b.SyntaxDef) if b.Settings["syntax"].(bool) { go func() { b.Highlighter.HighlightStates(b) b.Highlighter.HighlightMatches(b, 0, b.End().Y) screen.Redraw() }() } } } // ClearMatches clears all of the syntax highlighting for the buffer func (b *Buffer) ClearMatches() { for i := range b.lines { b.SetMatch(i, nil) b.SetState(i, nil) } } // IndentString returns this buffer's indent method (a tabstop or n spaces // depending on the settings) func (b *Buffer) IndentString(tabsize int) string { if b.Settings["tabstospaces"].(bool) { return util.Spaces(tabsize) } return "\t" } // SetCursors resets this buffer's cursors to a new list func (b *Buffer) SetCursors(c []*Cursor) { b.cursors = c b.EventHandler.cursors = b.cursors b.EventHandler.active = b.curCursor } // AddCursor adds a new cursor to the list func (b *Buffer) AddCursor(c *Cursor) { b.cursors = append(b.cursors, c) b.EventHandler.cursors = b.cursors b.EventHandler.active = b.curCursor b.UpdateCursors() } // SetCurCursor sets the current cursor func (b *Buffer) SetCurCursor(n int) { b.curCursor = n } // GetActiveCursor returns the main cursor in this buffer func (b *Buffer) GetActiveCursor() *Cursor { return b.cursors[b.curCursor] } // GetCursor returns the nth cursor func (b *Buffer) GetCursor(n int) *Cursor { return b.cursors[n] } // GetCursors returns the list of cursors in this buffer func (b *Buffer) GetCursors() []*Cursor { return b.cursors } // NumCursors returns the number of cursors func (b *Buffer) NumCursors() int { return len(b.cursors) } // MergeCursors merges any cursors that are at the same position // into one cursor func (b *Buffer) MergeCursors() { var cursors []*Cursor for i := 0; i < len(b.cursors); i++ { c1 := b.cursors[i] if c1 != nil { for j := 0; j < len(b.cursors); j++ { c2 := b.cursors[j] if c2 != nil && i != j && c1.Loc == c2.Loc { b.cursors[j] = nil } } cursors = append(cursors, c1) } } b.cursors = cursors for i := range b.cursors { b.cursors[i].Num = i } if b.curCursor >= len(b.cursors) { b.curCursor = len(b.cursors) - 1 } b.EventHandler.cursors = b.cursors b.EventHandler.active = b.curCursor } // UpdateCursors updates all the cursors indices func (b *Buffer) UpdateCursors() { b.EventHandler.cursors = b.cursors b.EventHandler.active = b.curCursor for i, c := range b.cursors { c.Num = i } } func (b *Buffer) RemoveCursor(i int) { copy(b.cursors[i:], b.cursors[i+1:]) b.cursors[len(b.cursors)-1] = nil b.cursors = b.cursors[:len(b.cursors)-1] b.curCursor = util.Clamp(b.curCursor, 0, len(b.cursors)-1) b.UpdateCursors() } // ClearCursors removes all extra cursors func (b *Buffer) ClearCursors() { for i := 1; i < len(b.cursors); i++ { b.cursors[i] = nil } b.cursors = b.cursors[:1] b.UpdateCursors() b.curCursor = 0 b.GetActiveCursor().Deselect(true) } // MoveLinesUp moves the range of lines up one row func (b *Buffer) MoveLinesUp(start int, end int) { if start < 1 || start >= end || end > len(b.lines) { return } l := string(b.LineBytes(start - 1)) if end == len(b.lines) { b.insert( Loc{ util.CharacterCount(b.lines[end-1].data), end - 1, }, []byte{'\n'}, ) } b.Insert( Loc{0, end}, l+"\n", ) b.Remove( Loc{0, start - 1}, Loc{0, start}, ) } // MoveLinesDown moves the range of lines down one row func (b *Buffer) MoveLinesDown(start int, end int) { if start < 0 || start >= end || end >= len(b.lines) { return } l := string(b.LineBytes(end)) b.Insert( Loc{0, start}, l+"\n", ) end++ b.Remove( Loc{0, end}, Loc{0, end + 1}, ) } var BracePairs = [][2]rune{ {'(', ')'}, {'{', '}'}, {'[', ']'}, } func (b *Buffer) findMatchingBrace(braceType [2]rune, start Loc, char rune) (Loc, bool) { var i int if char == braceType[0] { for y := start.Y; y < b.LinesNum(); y++ { l := []rune(string(b.LineBytes(y))) xInit := 0 if y == start.Y { xInit = start.X } for x := xInit; x < len(l); x++ { r := l[x] if r == braceType[0] { i++ } else if r == braceType[1] { i-- if i == 0 { return Loc{x, y}, true } } } } } else if char == braceType[1] { for y := start.Y; y >= 0; y-- { l := []rune(string(b.lines[y].data)) xInit := len(l) - 1 if y == start.Y { xInit = start.X } for x := xInit; x >= 0; x-- { r := l[x] if r == braceType[1] { i++ } else if r == braceType[0] { i-- if i == 0 { return Loc{x, y}, true } } } } } return start, false } // If there is a brace character (for example '{' or ']') at the given start location, // FindMatchingBrace returns the location of the matching brace for it (for example '}' // or '['). The second returned value is true if there was no matching brace found // for given starting location but it was found for the location one character left // of it. The third returned value is true if the matching brace was found at all. func (b *Buffer) FindMatchingBrace(start Loc) (Loc, bool, bool) { // TODO: maybe can be more efficient with utf8 package curLine := []rune(string(b.LineBytes(start.Y))) // first try to find matching brace for the given location (it has higher priority) if start.X >= 0 && start.X < len(curLine) { startChar := curLine[start.X] for _, bp := range BracePairs { if startChar == bp[0] || startChar == bp[1] { mb, found := b.findMatchingBrace(bp, start, startChar) if found { return mb, false, true } } } } if b.Settings["matchbraceleft"].(bool) { // failed to find matching brace for the given location, so try to find matching // brace for the location one character left of it if start.X-1 >= 0 && start.X-1 < len(curLine) { leftChar := curLine[start.X-1] left := Loc{start.X - 1, start.Y} for _, bp := range BracePairs { if leftChar == bp[0] || leftChar == bp[1] { mb, found := b.findMatchingBrace(bp, left, leftChar) if found { return mb, true, true } } } } } return start, false, false } // Retab changes all tabs to spaces or vice versa func (b *Buffer) Retab() { toSpaces := b.Settings["tabstospaces"].(bool) tabsize := util.IntOpt(b.Settings["tabsize"]) for i := 0; i < b.LinesNum(); i++ { l := b.LineBytes(i) ws := util.GetLeadingWhitespace(l) if len(ws) != 0 { if toSpaces { ws = bytes.ReplaceAll(ws, []byte{'\t'}, bytes.Repeat([]byte{' '}, tabsize)) } else { ws = bytes.ReplaceAll(ws, bytes.Repeat([]byte{' '}, tabsize), []byte{'\t'}) } } l = bytes.TrimLeft(l, " \t") b.Lock() b.lines[i].data = append(ws, l...) b.Unlock() b.MarkModified(i, i) } b.setModified() } // ParseCursorLocation turns a cursor location like 10:5 (LINE:COL) // into a loc func ParseCursorLocation(cursorPositions []string) (Loc, error) { startpos := Loc{0, 0} var err error // if no positions are available exit early if cursorPositions == nil { return startpos, errors.New("No cursor positions were provided.") } startpos.Y, err = strconv.Atoi(cursorPositions[0]) startpos.Y-- if err == nil { if len(cursorPositions) > 1 { startpos.X, err = strconv.Atoi(cursorPositions[1]) if startpos.X > 0 { startpos.X-- } } } return startpos, err } // Line returns the string representation of the given line number func (b *Buffer) Line(i int) string { return string(b.LineBytes(i)) } func (b *Buffer) Write(bytes []byte) (n int, err error) { b.EventHandler.InsertBytes(b.End(), bytes) return len(bytes), nil } func (b *Buffer) updateDiff(synchronous bool) { b.diffLock.Lock() defer b.diffLock.Unlock() b.diff = make(map[int]DiffStatus) if b.diffBase == nil { return } differ := dmp.New() if !synchronous { b.Lock() } bytes := b.Bytes() if !synchronous { b.Unlock() } baseRunes, bufferRunes, _ := differ.DiffLinesToRunes(string(b.diffBase), string(bytes)) diffs := differ.DiffMainRunes(baseRunes, bufferRunes, false) lineN := 0 for _, diff := range diffs { lineCount := len([]rune(diff.Text)) switch diff.Type { case dmp.DiffEqual: lineN += lineCount case dmp.DiffInsert: var status DiffStatus if b.diff[lineN] == DSDeletedAbove { status = DSModified } else { status = DSAdded } for i := 0; i < lineCount; i++ { b.diff[lineN] = status lineN++ } case dmp.DiffDelete: b.diff[lineN] = DSDeletedAbove } } } // UpdateDiff computes the diff between the diff base and the buffer content. // The update may be performed synchronously or asynchronously. // If an asynchronous update is already pending when UpdateDiff is called, // UpdateDiff does not schedule another update. func (b *Buffer) UpdateDiff() { if b.updateDiffTimer != nil { return } lineCount := b.LinesNum() if b.diffBaseLineCount > lineCount { lineCount = b.diffBaseLineCount } if lineCount < 1000 { b.updateDiff(true) } else if lineCount < 30000 { b.updateDiffTimer = time.AfterFunc(500*time.Millisecond, func() { b.updateDiffTimer = nil b.updateDiff(false) screen.Redraw() }) } else { // Don't compute diffs for very large files b.diffLock.Lock() b.diff = make(map[int]DiffStatus) b.diffLock.Unlock() } } // SetDiffBase sets the text that is used as the base for diffing the buffer content func (b *Buffer) SetDiffBase(diffBase []byte) { b.diffBase = diffBase if diffBase == nil { b.diffBaseLineCount = 0 } else { b.diffBaseLineCount = strings.Count(string(diffBase), "\n") } b.UpdateDiff() } // DiffStatus returns the diff status for a line in the buffer func (b *Buffer) DiffStatus(lineN int) DiffStatus { b.diffLock.RLock() defer b.diffLock.RUnlock() // Note that the zero value for DiffStatus is equal to DSUnchanged return b.diff[lineN] } // FindNextDiffLine returns the line number of the next block of diffs. // If `startLine` is already in a block of diffs, lines in that block are skipped. func (b *Buffer) FindNextDiffLine(startLine int, forward bool) (int, error) { if b.diff == nil { return 0, errors.New("no diff data") } startStatus, ok := b.diff[startLine] if !ok { startStatus = DSUnchanged } curLine := startLine for { curStatus, ok := b.diff[curLine] if !ok { curStatus = DSUnchanged } if curLine < 0 || curLine > b.LinesNum() { return 0, errors.New("no next diff hunk") } if curStatus != startStatus { if startStatus != DSUnchanged && curStatus == DSUnchanged { // Skip over the block of unchanged text startStatus = DSUnchanged } else { return curLine, nil } } if forward { curLine++ } else { curLine-- } } } // SearchMatch returns true if the given location is within a match of the last search. // It is used for search highlighting func (b *Buffer) SearchMatch(pos Loc) bool { return b.LineArray.SearchMatch(b, pos) } // WriteLog writes a string to the log buffer func WriteLog(s string) { LogBuf.EventHandler.Insert(LogBuf.End(), s) } // GetLogBuf returns the log buffer func GetLogBuf() *Buffer { return LogBuf } zyedidia-micro-6a62575/internal/buffer/backup.go0000664000175000017510000001075215125206537021131 0ustar nileshnileshpackage buffer import ( "errors" "fmt" "io/fs" "os" "path/filepath" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) const BackupMsg = `A backup was detected for: %s This likely means that micro crashed while editing this file, or another instance of micro is currently editing this file, or an error occurred while saving this file so it may be corrupted. The backup was created on %s and its path is: %s * 'recover' will apply the backup as unsaved changes to the current buffer. When the buffer is closed, the backup will be removed. * 'ignore' will ignore the backup, discarding its changes. The backup file will be removed. * 'abort' will abort the open operation, and instead open an empty buffer. Options: [r]ecover, [i]gnore, [a]bort: ` const backupSeconds = 8 type backupRequestType int const ( backupCreate = iota backupRemove ) type backupRequest struct { buf *SharedBuffer reqType backupRequestType } var requestedBackups map[*SharedBuffer]bool func init() { requestedBackups = make(map[*SharedBuffer]bool) } func (b *SharedBuffer) RequestBackup() { backupRequestChan <- backupRequest{buf: b, reqType: backupCreate} } func (b *SharedBuffer) CancelBackup() { backupRequestChan <- backupRequest{buf: b, reqType: backupRemove} } func handleBackupRequest(br backupRequest) { switch br.reqType { case backupCreate: // schedule periodic backup requestedBackups[br.buf] = true case backupRemove: br.buf.RemoveBackup() delete(requestedBackups, br.buf) } } func periodicBackup() { for buf := range requestedBackups { err := buf.Backup() if err == nil { delete(requestedBackups, buf) } } } func (b *SharedBuffer) backupDir() string { backupdir, err := util.ReplaceHome(b.Settings["backupdir"].(string)) if backupdir == "" || err != nil { backupdir = filepath.Join(config.ConfigDir, "backups") } return backupdir } func (b *SharedBuffer) keepBackup() bool { return b.forceKeepBackup || b.Settings["permbackup"].(bool) } func (b *SharedBuffer) writeBackup(path string) (string, string, error) { backupdir := b.backupDir() if _, err := os.Stat(backupdir); err != nil { if !errors.Is(err, fs.ErrNotExist) { return "", "", err } if err = os.Mkdir(backupdir, os.ModePerm); err != nil { return "", "", err } } name, resolveName := util.DetermineEscapePath(backupdir, path) tmp := name + util.BackupSuffix _, err := b.overwriteFile(tmp) if err != nil { os.Remove(tmp) return name, resolveName, err } err = os.Rename(tmp, name) if err != nil { os.Remove(tmp) return name, resolveName, err } if resolveName != "" { err = util.SafeWrite(resolveName, []byte(path), true) if err != nil { return name, resolveName, err } } return name, resolveName, nil } func (b *SharedBuffer) removeBackup(path string, resolveName string) { os.Remove(path) if resolveName != "" { os.Remove(resolveName) } } // Backup saves the buffer to the backups directory func (b *SharedBuffer) Backup() error { if !b.Settings["backup"].(bool) || b.Path == "" || b.Type != BTDefault { return nil } _, _, err := b.writeBackup(b.AbsPath) return err } // RemoveBackup removes any backup file associated with this buffer func (b *SharedBuffer) RemoveBackup() { if b.keepBackup() || b.Path == "" || b.Type != BTDefault { return } f, resolveName := util.DetermineEscapePath(b.backupDir(), b.AbsPath) b.removeBackup(f, resolveName) } // ApplyBackup applies the corresponding backup file to this buffer (if one exists) // Returns true if a backup was applied func (b *SharedBuffer) ApplyBackup(fsize int64) (bool, bool) { if b.Settings["backup"].(bool) && !b.Settings["permbackup"].(bool) && len(b.Path) > 0 && b.Type == BTDefault { backupfile, resolveName := util.DetermineEscapePath(b.backupDir(), b.AbsPath) if info, err := os.Stat(backupfile); err == nil { backup, err := os.Open(backupfile) if err == nil { defer backup.Close() t := info.ModTime() msg := fmt.Sprintf(BackupMsg, b.Path, t.Format("Mon Jan _2 at 15:04, 2006"), backupfile) choice := screen.TermPrompt(msg, []string{"r", "i", "a", "recover", "ignore", "abort"}, true) if choice%3 == 0 { // recover b.LineArray = NewLineArray(uint64(fsize), FFAuto, backup) b.setModified() return true, true } else if choice%3 == 1 { // delete b.removeBackup(backupfile, resolveName) } else if choice%3 == 2 { return false, false } } } } return false, true } zyedidia-micro-6a62575/internal/buffer/autocomplete.go0000664000175000017510000001154315125206537022364 0ustar nileshnileshpackage buffer import ( "bytes" "io/fs" "os" "sort" "strings" "github.com/zyedidia/micro/v2/internal/util" ) // A Completer is a function that takes a buffer and returns info // describing what autocompletions should be inserted at the current // cursor location // It returns a list of string suggestions which will be inserted at // the current cursor location if selected as well as a list of // suggestion names which can be displayed in an autocomplete box or // other UI element type Completer func(*Buffer) ([]string, []string) func (b *Buffer) GetSuggestions() { } // Autocomplete starts the autocomplete process func (b *Buffer) Autocomplete(c Completer) bool { b.Completions, b.Suggestions = c(b) if len(b.Completions) != len(b.Suggestions) || len(b.Completions) == 0 { return false } b.CurSuggestion = -1 b.CycleAutocomplete(true) return true } // CycleAutocomplete moves to the next suggestion func (b *Buffer) CycleAutocomplete(forward bool) { prevSuggestion := b.CurSuggestion if forward { b.CurSuggestion++ } else { b.CurSuggestion-- } if b.CurSuggestion >= len(b.Suggestions) { b.CurSuggestion = 0 } else if b.CurSuggestion < 0 { b.CurSuggestion = len(b.Suggestions) - 1 } c := b.GetActiveCursor() start := c.Loc end := c.Loc if prevSuggestion < len(b.Suggestions) && prevSuggestion >= 0 { start = end.Move(-util.CharacterCountInString(b.Completions[prevSuggestion]), b) } b.Replace(start, end, b.Completions[b.CurSuggestion]) if len(b.Suggestions) > 1 { b.HasSuggestions = true } } // GetWord gets the most recent word separated by any separator // (whitespace, punctuation, any non alphanumeric character) func (b *Buffer) GetWord() ([]byte, int) { c := b.GetActiveCursor() l := b.LineBytes(c.Y) l = util.SliceStart(l, c.X) if c.X == 0 || util.IsWhitespace(b.RuneAt(c.Loc.Move(-1, b))) { return []byte{}, -1 } if util.IsNonWordChar(b.RuneAt(c.Loc.Move(-1, b))) { return []byte{}, c.X } args := bytes.FieldsFunc(l, util.IsNonWordChar) input := args[len(args)-1] return input, c.X - util.CharacterCount(input) } // GetArg gets the most recent word (separated by ' ' only) func (b *Buffer) GetArg() (string, int) { c := b.GetActiveCursor() l := b.LineBytes(c.Y) l = util.SliceStart(l, c.X) args := bytes.Split(l, []byte{' '}) input := string(args[len(args)-1]) argstart := 0 for i, a := range args { if i == len(args)-1 { break } argstart += util.CharacterCount(a) + 1 } return input, argstart } // FileComplete autocompletes filenames func FileComplete(b *Buffer) ([]string, []string) { c := b.GetActiveCursor() input, argstart := b.GetArg() sep := string(os.PathSeparator) dirs := strings.Split(input, sep) var files []fs.DirEntry var err error if len(dirs) > 1 { directories := strings.Join(dirs[:len(dirs)-1], sep) + sep directories, _ = util.ReplaceHome(directories) files, err = os.ReadDir(directories) } else { files, err = os.ReadDir(".") } if err != nil { return nil, nil } var suggestions []string for _, f := range files { name := f.Name() if f.IsDir() { name += sep } if strings.HasPrefix(name, dirs[len(dirs)-1]) { suggestions = append(suggestions, name) } } sort.Strings(suggestions) completions := make([]string, len(suggestions)) for i := range suggestions { var complete string if len(dirs) > 1 { complete = strings.Join(dirs[:len(dirs)-1], sep) + sep + suggestions[i] } else { complete = suggestions[i] } completions[i] = util.SliceEndStr(complete, c.X-argstart) } return completions, suggestions } // BufferComplete autocompletes based on previous words in the buffer func BufferComplete(b *Buffer) ([]string, []string) { c := b.GetActiveCursor() input, argstart := b.GetWord() if argstart == -1 { return []string{}, []string{} } inputLen := util.CharacterCount(input) suggestionsSet := make(map[string]struct{}) var suggestions []string for i := c.Y; i >= 0; i-- { l := b.LineBytes(i) words := bytes.FieldsFunc(l, util.IsNonWordChar) for _, w := range words { if bytes.HasPrefix(w, input) && util.CharacterCount(w) > inputLen { strw := string(w) if _, ok := suggestionsSet[strw]; !ok { suggestionsSet[strw] = struct{}{} suggestions = append(suggestions, strw) } } } } for i := c.Y + 1; i < b.LinesNum(); i++ { l := b.LineBytes(i) words := bytes.FieldsFunc(l, util.IsNonWordChar) for _, w := range words { if bytes.HasPrefix(w, input) && util.CharacterCount(w) > inputLen { strw := string(w) if _, ok := suggestionsSet[strw]; !ok { suggestionsSet[strw] = struct{}{} suggestions = append(suggestions, strw) } } } } if len(suggestions) > 1 { suggestions = append(suggestions, string(input)) } completions := make([]string, len(suggestions)) for i := range suggestions { completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart) } return completions, suggestions } zyedidia-micro-6a62575/internal/action/0000775000175000017510000000000015125206537017334 5ustar nileshnileshzyedidia-micro-6a62575/internal/action/termpane.go0000664000175000017510000001220115125206537021472 0ustar nileshnileshpackage action import ( "errors" "runtime" "github.com/micro-editor/tcell/v2" "github.com/micro-editor/terminal" "github.com/zyedidia/micro/v2/internal/clipboard" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/display" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/shell" ) type TermKeyAction func(*TermPane) var TermBindings *KeyTree func init() { TermBindings = NewKeyTree() } func TermKeyActionGeneral(a TermKeyAction) PaneKeyAction { return func(p Pane) bool { a(p.(*TermPane)) return true } } func TermMapEvent(k Event, action string) { config.Bindings["terminal"][k.Name()] = action switch e := k.(type) { case KeyEvent, KeySequenceEvent, RawEvent: termMapKey(e, action) case MouseEvent: termMapMouse(e, action) } } func termMapKey(k Event, action string) { if f, ok := TermKeyActions[action]; ok { TermBindings.RegisterKeyBinding(k, TermKeyActionGeneral(f)) } } func termMapMouse(k MouseEvent, action string) { // TODO: map mouse termMapKey(k, action) } type TermPane struct { *shell.Terminal display.Window mouseReleased bool id uint64 tab *Tab } func NewTermPane(x, y, w, h int, t *shell.Terminal, id uint64, tab *Tab) (*TermPane, error) { if !TermEmuSupported { return nil, errors.New("Terminal emulator is not supported on this system") } th := new(TermPane) th.Terminal = t th.id = id th.mouseReleased = true th.Window = display.NewTermWindow(x, y, w, h, t) th.tab = tab return th, nil } func (t *TermPane) ID() uint64 { return t.id } func (t *TermPane) SetID(i uint64) { t.id = i } func (t *TermPane) Name() string { return t.Terminal.Name() } func (t *TermPane) SetTab(tab *Tab) { t.tab = tab } func (t *TermPane) Tab() *Tab { return t.tab } func (t *TermPane) Close() {} // Quit closes this termpane func (t *TermPane) Quit() { t.Close() if len(MainTab().Panes) > 1 { t.Unsplit() } else if len(Tabs.List) > 1 { Tabs.RemoveTab(t.id) } else { screen.Screen.Fini() InfoBar.Close() runtime.Goexit() } } // Unsplit removes this split func (t *TermPane) Unsplit() { n := MainTab().GetNode(t.id) n.Unsplit() MainTab().RemovePane(MainTab().GetPane(t.id)) MainTab().Resize() MainTab().SetActive(len(MainTab().Panes) - 1) } // HandleEvent handles a tcell event by forwarding it to the terminal emulator // If the event is a mouse event and the program running in the emulator // does not have mouse support, the emulator will support selections and // copy-paste func (t *TermPane) HandleEvent(event tcell.Event) { if e, ok := event.(*tcell.EventKey); ok { ke := keyEvent(e) action, more := TermBindings.NextEvent(ke, nil) if !more { if action != nil { action(t) TermBindings.ResetEvents() return } TermBindings.ResetEvents() } if more { return } if t.Status == shell.TTDone { switch e.Key() { case tcell.KeyEscape, tcell.KeyCtrlQ, tcell.KeyEnter: t.Close() t.Quit() default: } } if e.Key() == tcell.KeyCtrlC && t.HasSelection() { clipboard.Write(t.GetSelection(t.GetView().Width), clipboard.ClipboardReg) InfoBar.Message("Copied selection to clipboard") } else if t.Status != shell.TTDone { t.WriteString(event.EscSeq()) } } else if _, ok := event.(*tcell.EventPaste); ok { if t.Status != shell.TTDone { t.WriteString(event.EscSeq()) } } else if e, ok := event.(*tcell.EventMouse); !ok || t.State.Mode(terminal.ModeMouseMask) { // t.WriteString(event.EscSeq()) } else { x, y := e.Position() v := t.GetView() x -= v.X y -= v.Y if e.Buttons() == tcell.Button1 { if !t.mouseReleased { // drag t.Selection[1].X = x t.Selection[1].Y = y } else { t.Selection[0].X = x t.Selection[0].Y = y t.Selection[1].X = x t.Selection[1].Y = y } t.mouseReleased = false } else if e.Buttons() == tcell.ButtonNone { if !t.mouseReleased { t.Selection[1].X = x t.Selection[1].Y = y } t.mouseReleased = true } } } // HandleTermClose is called when a terminal has finished its job // and should be closed. If that terminal is this termpane's terminal, // HandleTermClose will close the terminal and the termpane itself. func (t *TermPane) HandleTermClose() { if t.Status == shell.TTClose { t.Quit() } } // Exit closes the termpane func (t *TermPane) Exit() { t.Terminal.Close() t.Quit() } // CommandMode opens the termpane's command mode func (t *TermPane) CommandMode() { InfoBar.Prompt("> ", "", "TerminalCommand", nil, func(resp string, canceled bool) { if !canceled { t.HandleCommand(resp) } }) } // NextSplit moves to the next split func (t *TermPane) NextSplit() { a := t.tab.active if a < len(t.tab.Panes)-1 { a++ } else { a = 0 } t.tab.SetActive(a) } // HandleCommand handles a command for the term pane func (t *TermPane) HandleCommand(input string) { InfoBar.Error("Commands are unsupported in term for now") } // TermKeyActions contains the list of all possible key actions the termpane could execute var TermKeyActions = map[string]TermKeyAction{ "Exit": (*TermPane).Exit, "CommandMode": (*TermPane).CommandMode, "NextSplit": (*TermPane).NextSplit, } zyedidia-micro-6a62575/internal/action/terminal_unsupported.go0000664000175000017510000000067515125206537024156 0ustar nileshnilesh//go:build plan9 || nacl || windows package action import "errors" // TermEmuSupported is a constant that marks if the terminal emulator is supported const TermEmuSupported = false // RunTermEmulator returns an error for unsupported systems (non-unix systems func RunTermEmulator(input string, wait bool, getOutput bool, callback func(out string, userargs []any), userargs []any) error { return errors.New("Unsupported operating system") } zyedidia-micro-6a62575/internal/action/terminal_supported.go0000664000175000017510000000244115125206537023604 0ustar nileshnilesh//go:build linux || darwin || dragonfly || solaris || openbsd || netbsd || freebsd package action import ( shellquote "github.com/kballard/go-shellquote" "github.com/zyedidia/micro/v2/internal/shell" ) // TermEmuSupported is a constant that marks if the terminal emulator is supported const TermEmuSupported = true // RunTermEmulator starts a terminal emulator from a bufpane with the given input (command) // if wait is true it will wait for the user to exit by pressing enter once the executable has terminated // if getOutput is true it will redirect the stdout of the process to a pipe which will be passed to the // callback which is a function that takes a string and a list of optional user arguments func RunTermEmulator(h *BufPane, input string, wait bool, getOutput bool, callback func(out string, userargs []any), userargs []any) error { args, err := shellquote.Split(input) if err != nil { return err } if len(args) == 0 { return nil } t := new(shell.Terminal) err = t.Start(args, getOutput, wait, callback, userargs) if err != nil { return err } h.AddTab() id := MainTab().Panes[0].ID() v := h.GetView() tp, err := NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab()) if err != nil { return err } MainTab().Panes[0] = tp MainTab().SetActive(0) return nil } zyedidia-micro-6a62575/internal/action/tab.go0000664000175000017510000002173515125206537020441 0ustar nileshnileshpackage action import ( luar "layeh.com/gopher-luar" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/display" ulua "github.com/zyedidia/micro/v2/internal/lua" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/views" ) // The TabList is a list of tabs and a window to display the tab bar // at the top of the screen type TabList struct { *display.TabWindow List []*Tab } // NewTabList creates a TabList from a list of buffers by creating a Tab // for each buffer func NewTabList(bufs []*buffer.Buffer) *TabList { w, h := screen.Screen.Size() iOffset := config.GetInfoBarOffset() tl := new(TabList) tl.List = make([]*Tab, len(bufs)) if len(bufs) > 1 { for i, b := range bufs { tl.List[i] = NewTabFromBuffer(0, 1, w, h-1-iOffset, b) } } else { tl.List[0] = NewTabFromBuffer(0, 0, w, h-iOffset, bufs[0]) } tl.TabWindow = display.NewTabWindow(w, 0) tl.Names = make([]string, len(bufs)) return tl } // UpdateNames makes sure that the list of names the tab window has access to is // correct func (t *TabList) UpdateNames() { t.Names = t.Names[:0] for _, p := range t.List { t.Names = append(t.Names, p.Panes[p.active].Name()) } } // AddTab adds a new tab to this TabList func (t *TabList) AddTab(p *Tab) { t.List = append(t.List, p) t.Resize() t.UpdateNames() } // RemoveTab removes a tab with the given id from the TabList func (t *TabList) RemoveTab(id uint64) { for i, p := range t.List { if len(p.Panes) == 0 { continue } if p.Panes[0].ID() == id { copy(t.List[i:], t.List[i+1:]) t.List[len(t.List)-1] = nil t.List = t.List[:len(t.List)-1] if t.Active() >= len(t.List) { t.SetActive(len(t.List) - 1) } t.Resize() t.UpdateNames() return } } } // Resize resizes all elements within the tab list // One thing to note is that when there is only 1 tab // the tab bar should not be drawn so resizing must take // that into account func (t *TabList) Resize() { w, h := screen.Screen.Size() iOffset := config.GetInfoBarOffset() InfoBar.Resize(w, h-1) if len(t.List) > 1 { for _, p := range t.List { p.Y = 1 p.Node.Resize(w, h-1-iOffset) p.Resize() } } else if len(t.List) == 1 { t.List[0].Y = 0 t.List[0].Node.Resize(w, h-iOffset) t.List[0].Resize() } t.TabWindow.Resize(w, h) } // HandleEvent checks for a resize event or a mouse event on the tab bar // otherwise it will forward the event to the currently active tab func (t *TabList) HandleEvent(event tcell.Event) { switch e := event.(type) { case *tcell.EventResize: t.Resize() case *tcell.EventMouse: mx, my := e.Position() switch e.Buttons() { case tcell.Button1: if my == t.Y && len(t.List) > 1 { if mx == 0 { t.Scroll(-4) } else if mx == t.Width-1 { t.Scroll(4) } else { ind := t.LocFromVisual(buffer.Loc{mx, my}) if ind != -1 { t.SetActive(ind) } } return } case tcell.ButtonNone: if t.List[t.Active()].release { // Mouse release received, while already released t.ResetMouse() return } case tcell.WheelUp: if my == t.Y && len(t.List) > 1 { t.Scroll(4) return } case tcell.WheelDown: if my == t.Y && len(t.List) > 1 { t.Scroll(-4) return } } } t.List[t.Active()].HandleEvent(event) } // Display updates the names and then displays the tab bar func (t *TabList) Display() { t.UpdateNames() if len(t.List) > 1 { t.TabWindow.Display() } } func (t *TabList) SetActive(a int) { t.TabWindow.SetActive(a) for i, p := range t.List { if i == a { if !p.isActive { p.isActive = true err := config.RunPluginFn("onSetActive", luar.New(ulua.L, p.CurPane())) if err != nil { screen.TermMessage(err) } } } else { p.isActive = false } } } // ResetMouse resets the mouse release state after the screen was stopped // or the pane changed. // This prevents situations in which mouse releases are received at the wrong place // and the mouse state is still pressed. func (t *TabList) ResetMouse() { for _, tab := range t.List { if !tab.release && tab.resizing != nil { tab.resizing = nil } tab.release = true for _, p := range tab.Panes { if bp, ok := p.(*BufPane); ok { bp.resetMouse() } } } } // CloseTerms notifies term panes that a terminal job has finished. func (t *TabList) CloseTerms() { for _, tab := range t.List { for _, p := range tab.Panes { if tp, ok := p.(*TermPane); ok { tp.HandleTermClose() } } } } // Tabs is the global tab list var Tabs *TabList func InitTabs(bufs []*buffer.Buffer) { multiopen := config.GetGlobalOption("multiopen").(string) if multiopen == "tab" { Tabs = NewTabList(bufs) } else { Tabs = NewTabList(bufs[:1]) for _, b := range bufs[1:] { if multiopen == "vsplit" { MainTab().CurPane().VSplitBuf(b) } else { // default hsplit MainTab().CurPane().HSplitBuf(b) } } } screen.RestartCallback = Tabs.ResetMouse } func MainTab() *Tab { return Tabs.List[Tabs.Active()] } // A Tab represents a single tab // It consists of a list of edit panes (the open buffers), // a split tree (stored as just the root node), and a uiwindow // to display the UI elements like the borders between splits type Tab struct { *views.Node *display.UIWindow isActive bool Panes []Pane active int resizing *views.Node // node currently being resized // captures whether the mouse is released release bool } // NewTabFromBuffer creates a new tab from the given buffer func NewTabFromBuffer(x, y, width, height int, b *buffer.Buffer) *Tab { t := new(Tab) t.Node = views.NewRoot(x, y, width, height) t.UIWindow = display.NewUIWindow(t.Node) t.release = true e := NewBufPaneFromBuf(b, t) e.SetID(t.ID()) t.Panes = append(t.Panes, e) return t } func NewTabFromPane(x, y, width, height int, pane Pane) *Tab { t := new(Tab) t.Node = views.NewRoot(x, y, width, height) t.UIWindow = display.NewUIWindow(t.Node) t.release = true pane.SetTab(t) pane.SetID(t.ID()) t.Panes = append(t.Panes, pane) return t } // HandleEvent takes a tcell event and usually dispatches it to the current // active pane. However if the event is a resize or a mouse event where the user // is interacting with the UI (resizing splits) then the event is consumed here // If the event is a mouse press event in a pane, that pane will become active // and get the event func (t *Tab) HandleEvent(event tcell.Event) { switch e := event.(type) { case *tcell.EventMouse: mx, my := e.Position() btn := e.Buttons() switch { case btn & ^(tcell.WheelUp|tcell.WheelDown|tcell.WheelLeft|tcell.WheelRight) != tcell.ButtonNone: // button press or drag wasReleased := t.release t.release = false if btn == tcell.Button1 { if t.resizing != nil { var size int if t.resizing.Kind == views.STVert { size = mx - t.resizing.X } else { size = my - t.resizing.Y + 1 } t.resizing.ResizeSplit(size) t.Resize() return } if wasReleased { t.resizing = t.GetMouseSplitNode(buffer.Loc{mx, my}) if t.resizing != nil { return } } } if wasReleased { for i, p := range t.Panes { v := p.GetView() inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height if inpane { t.SetActive(i) break } } } case btn == tcell.ButtonNone: // button release t.release = true if t.resizing != nil { t.resizing = nil return } default: // wheel move for _, p := range t.Panes { v := p.GetView() inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height if inpane { p.HandleEvent(event) return } } } } t.Panes[t.active].HandleEvent(event) } // SetActive changes the currently active pane to the specified index func (t *Tab) SetActive(i int) { t.active = i for j, p := range t.Panes { if j == i { p.SetActive(true) } else { p.SetActive(false) } } } // AddPane adds a pane at a given index func (t *Tab) AddPane(pane Pane, i int) { if len(t.Panes) == i { t.Panes = append(t.Panes, pane) return } t.Panes = append(t.Panes[:i+1], t.Panes[i:]...) t.Panes[i] = pane } // GetPane returns the pane with the given split index func (t *Tab) GetPane(splitid uint64) int { for i, p := range t.Panes { if p.ID() == splitid { return i } } return 0 } // Remove pane removes the pane with the given index func (t *Tab) RemovePane(i int) { copy(t.Panes[i:], t.Panes[i+1:]) t.Panes[len(t.Panes)-1] = nil t.Panes = t.Panes[:len(t.Panes)-1] } // Resize resizes all panes according to their corresponding split nodes func (t *Tab) Resize() { for _, p := range t.Panes { n := t.GetNode(p.ID()) pv := p.GetView() offset := 0 if n.X != 0 { offset = 1 } pv.X, pv.Y = n.X+offset, n.Y p.SetView(pv) p.Resize(n.W-offset, n.H) } } // CurPane returns the currently active pane func (t *Tab) CurPane() *BufPane { p, ok := t.Panes[t.active].(*BufPane) if !ok { return nil } return p } zyedidia-micro-6a62575/internal/action/rawpane.go0000664000175000017510000000174415125206537021326 0ustar nileshnileshpackage action import ( "fmt" "reflect" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/display" ) type RawPane struct { *BufPane } func NewRawPaneFromWin(b *buffer.Buffer, win display.BWindow, tab *Tab) *RawPane { rh := new(RawPane) rh.BufPane = NewBufPane(b, win, tab) return rh } func NewRawPane(tab *Tab) *RawPane { b := buffer.NewBufferFromString("", "", buffer.BTRaw) b.SetName("Raw event viewer") w := display.NewBufWindow(0, 0, 0, 0, b) return NewRawPaneFromWin(b, w, tab) } func (h *RawPane) HandleEvent(event tcell.Event) { switch e := event.(type) { case *tcell.EventKey: if e.Key() == tcell.KeyCtrlQ { h.Quit() } } h.Buf.Insert(h.Cursor.Loc, reflect.TypeOf(event).String()[7:]) e, err := ConstructEvent(event) if err == nil { h.Buf.Insert(h.Cursor.Loc, fmt.Sprintf(": %s", e.Name())) } h.Buf.Insert(h.Cursor.Loc, fmt.Sprintf(": %q\n", event.EscSeq())) h.Relocate() } zyedidia-micro-6a62575/internal/action/pane.go0000664000175000017510000000041515125206537020606 0ustar nileshnileshpackage action import ( "github.com/zyedidia/micro/v2/internal/display" ) // A Pane is a general interface for a window in the editor. type Pane interface { Handler display.Window ID() uint64 SetID(i uint64) Name() string Close() SetTab(t *Tab) Tab() *Tab } zyedidia-micro-6a62575/internal/action/keytree.go0000664000175000017510000001521115125206537021333 0ustar nileshnileshpackage action import ( "bytes" "github.com/micro-editor/tcell/v2" ) type PaneKeyAction func(Pane) bool type PaneMouseAction func(Pane, *tcell.EventMouse) bool type PaneKeyAnyAction func(Pane, []KeyEvent) bool // A KeyTreeNode stores a single node in the KeyTree (trie). The // children are stored as a map, and any node may store a list of // actions (the list will be nil if no actions correspond to a certain // node) type KeyTreeNode struct { children map[Event]*KeyTreeNode // Only one of these actions may be active in the current // mode, and only one will be returned. If multiple actions // are active, it is undefined which one will be the one // returned. actions []TreeAction } func NewKeyTreeNode() *KeyTreeNode { n := new(KeyTreeNode) n.children = make(map[Event]*KeyTreeNode) n.actions = []TreeAction{} return n } // A TreeAction stores an action, and a set of mode constraints for // the action to be active. type TreeAction struct { // only one of these can be non-nil action PaneKeyAction any PaneKeyAnyAction mouse PaneMouseAction modes []ModeConstraint } // A KeyTree is a data structure for storing keybindings. It maps // key events to actions, and maintains a set of currently enabled // modes, which affects the action that is returned for a key event. // The tree acts like a Trie for Events to handle sequence events. type KeyTree struct { root *KeyTreeNode modes map[string]bool cursor KeyTreeCursor } // A KeyTreeCursor keeps track of the current location within the // tree, and stores any information from previous events that may // be needed to execute the action (values of wildcard events or // mouse events) type KeyTreeCursor struct { node *KeyTreeNode recordedEvents []Event wildcards []KeyEvent mouseInfo *tcell.EventMouse } // MakeClosure uses the information stored in a key tree cursor to construct // a PaneKeyAction from a TreeAction (which may have a PaneKeyAction, PaneMouseAction, // or AnyAction) func (k *KeyTreeCursor) MakeClosure(a TreeAction) PaneKeyAction { if a.action != nil { return a.action } else if a.any != nil { return func(p Pane) bool { return a.any(p, k.wildcards) } } else if a.mouse != nil { return func(p Pane) bool { return a.mouse(p, k.mouseInfo) } } return nil } // NewKeyTree allocates and returns an empty key tree func NewKeyTree() *KeyTree { root := NewKeyTreeNode() tree := new(KeyTree) tree.root = root tree.modes = make(map[string]bool) tree.cursor = KeyTreeCursor{ node: root, wildcards: []KeyEvent{}, mouseInfo: nil, } return tree } // A ModeConstraint specifies that an action can only be executed // while a certain mode is enabled or disabled. type ModeConstraint struct { mode string disabled bool } // RegisterKeyBinding registers a PaneKeyAction with an Event. func (k *KeyTree) RegisterKeyBinding(e Event, a PaneKeyAction) { k.registerBinding(e, TreeAction{ action: a, any: nil, mouse: nil, modes: nil, }) } // RegisterKeyAnyBinding registers a PaneKeyAnyAction with an Event. // The event should contain an "any" event. func (k *KeyTree) RegisterKeyAnyBinding(e Event, a PaneKeyAnyAction) { k.registerBinding(e, TreeAction{ action: nil, any: a, mouse: nil, modes: nil, }) } // RegisterMouseBinding registers a PaneMouseAction with an Event. // The event should contain a mouse event. func (k *KeyTree) RegisterMouseBinding(e Event, a PaneMouseAction) { k.registerBinding(e, TreeAction{ action: nil, any: nil, mouse: a, modes: nil, }) } func (k *KeyTree) registerBinding(e Event, a TreeAction) { switch ev := e.(type) { case KeyEvent, MouseEvent, RawEvent: newNode, ok := k.root.children[e] if !ok { newNode = NewKeyTreeNode() k.root.children[e] = newNode } // newNode.actions = append(newNode.actions, a) newNode.actions = []TreeAction{a} case KeySequenceEvent: n := k.root for _, key := range ev.keys { newNode, ok := n.children[key] if !ok { newNode = NewKeyTreeNode() n.children[key] = newNode } n = newNode } // n.actions = append(n.actions, a) n.actions = []TreeAction{a} } } // NextEvent returns the action for the current sequence where e is the next // event. Even if the action was registered as a PaneKeyAnyAction or PaneMouseAction, // it will be returned as a PaneKeyAction closure where the appropriate arguments // have been provided. // If no action is associated with the given Event, or mode constraints are not // met for that action, nil is returned. // A boolean is returned to indicate if there is a conflict with this action. A // conflict occurs when there is an active action for this event but there are // bindings associated with further sequences starting with this event. The // calling function can decide what to do about the conflict (e.g. use a // timeout). func (k *KeyTree) NextEvent(e Event, mouse *tcell.EventMouse) (PaneKeyAction, bool) { n := k.cursor.node c, ok := n.children[e] if !ok { return nil, false } more := len(c.children) > 0 k.cursor.node = c k.cursor.recordedEvents = append(k.cursor.recordedEvents, e) switch ev := e.(type) { case KeyEvent: if ev.any { k.cursor.wildcards = append(k.cursor.wildcards, ev) } case MouseEvent: k.cursor.mouseInfo = mouse } if len(c.actions) > 0 { // check if actions are active for _, a := range c.actions { active := true for _, mc := range a.modes { // if any mode constraint is not met, the action is not active hasMode := k.modes[mc.mode] if hasMode != mc.disabled { active = false } } if active { // the first active action to be found is returned return k.cursor.MakeClosure(a), more } } } return nil, more } // ResetEvents sets the current sequence back to the initial value. func (k *KeyTree) ResetEvents() { k.cursor.node = k.root k.cursor.wildcards = []KeyEvent{} k.cursor.recordedEvents = []Event{} k.cursor.mouseInfo = nil } // RecordedEventsStr returns the list of recorded events as a string func (k *KeyTree) RecordedEventsStr() string { buf := &bytes.Buffer{} for _, e := range k.cursor.recordedEvents { buf.WriteString(e.Name()) } return buf.String() } // DeleteBinding removes any currently active actions associated with the // given event. func (k *KeyTree) DeleteBinding(e Event) { } // DeleteAllBindings removes all actions associated with the given event, // regardless of whether they are active or not. func (k *KeyTree) DeleteAllBindings(e Event) { } // SetMode enables or disabled a given mode func (k *KeyTree) SetMode(mode string, en bool) { k.modes[mode] = en } // HasMode returns if the given mode is currently active func (k *KeyTree) HasMode(mode string) bool { return k.modes[mode] } zyedidia-micro-6a62575/internal/action/infopane.go0000664000175000017510000001355115125206537021467 0ustar nileshnileshpackage action import ( "bytes" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/display" "github.com/zyedidia/micro/v2/internal/info" "github.com/zyedidia/micro/v2/internal/util" ) type InfoKeyAction func(*InfoPane) var InfoBindings *KeyTree var InfoBufBindings *KeyTree func init() { InfoBindings = NewKeyTree() InfoBufBindings = NewKeyTree() } func InfoMapEvent(k Event, action string) { config.Bindings["command"][k.Name()] = action switch e := k.(type) { case KeyEvent, KeySequenceEvent, RawEvent: infoMapKey(e, action) case MouseEvent: infoMapMouse(e, action) } } func infoMapKey(k Event, action string) { if f, ok := InfoKeyActions[action]; ok { InfoBindings.RegisterKeyBinding(k, InfoKeyActionGeneral(f)) } else if f, ok := BufKeyActions[action]; ok { InfoBufBindings.RegisterKeyBinding(k, BufKeyActionGeneral(f)) } } func infoMapMouse(k MouseEvent, action string) { // TODO: map mouse if f, ok := BufMouseActions[action]; ok { InfoBufBindings.RegisterMouseBinding(k, BufMouseActionGeneral(f)) } else { infoMapKey(k, action) } } func InfoKeyActionGeneral(a InfoKeyAction) PaneKeyAction { return func(p Pane) bool { a(p.(*InfoPane)) return true } } type InfoPane struct { *BufPane *info.InfoBuf } func NewInfoPane(ib *info.InfoBuf, w display.BWindow, tab *Tab) *InfoPane { ip := new(InfoPane) ip.InfoBuf = ib ip.BufPane = NewBufPane(ib.Buffer, w, tab) ip.BufPane.bindings = InfoBufBindings return ip } func NewInfoBar() *InfoPane { ib := info.NewBuffer() w := display.NewInfoWindow(ib) return NewInfoPane(ib, w, nil) } func (h *InfoPane) Close() { h.InfoBuf.Close() h.BufPane.Close() } func (h *InfoPane) HandleEvent(event tcell.Event) { switch e := event.(type) { case *tcell.EventResize: // TODO case *tcell.EventKey: ke := keyEvent(e) done := h.DoKeyEvent(ke) hasYN := h.HasYN if e.Key() == tcell.KeyRune && hasYN { y := e.Rune() == 'y' || e.Rune() == 'Y' n := e.Rune() == 'n' || e.Rune() == 'N' if y || n { h.YNResp = y h.DonePrompt(false) InfoBindings.ResetEvents() InfoBufBindings.ResetEvents() } } if e.Key() == tcell.KeyRune && !done && !hasYN { h.DoRuneInsert(e.Rune()) done = true } if done && h.HasPrompt && !hasYN { resp := string(h.LineBytes(0)) hist := h.History[h.PromptType] if resp != hist[h.HistoryNum] { h.HistoryNum = len(hist) - 1 hist[h.HistoryNum] = resp h.HistorySearch = false } if h.EventCallback != nil { h.EventCallback(resp) } } default: h.BufPane.HandleEvent(event) } } // DoKeyEvent executes a key event for the command bar, doing any overridden actions. // Returns true if the action was executed OR if there are more keys remaining // to process before executing an action (if this is a key sequence event). // Returns false if no action found. func (h *InfoPane) DoKeyEvent(e KeyEvent) bool { action, more := InfoBindings.NextEvent(e, nil) if action != nil && !more { action(h) InfoBindings.ResetEvents() return true } else if action == nil && !more { InfoBindings.ResetEvents() // return false //TODO:? } if !more { // If no infopane action found, try to find a bufpane action. // // TODO: this is buggy. For example, if the command bar has the following // two bindings: // // "": "HistoryUp", // "": "Paste", // // the 2nd binding (with a bufpane action) doesn't work, since // has been already consumed by the 1st binding (with an infopane action). // // We should either iterate both InfoBindings and InfoBufBindings keytrees // together, or just use the same keytree for both infopane and bufpane // bindings. action, more = InfoBufBindings.NextEvent(e, nil) if action != nil && !more { action(h.BufPane) InfoBufBindings.ResetEvents() return true } else if action == nil && !more { InfoBufBindings.ResetEvents() } } return more } // HistoryUp cycles history up func (h *InfoPane) HistoryUp() { h.UpHistory(h.History[h.PromptType]) } // HistoryDown cycles history down func (h *InfoPane) HistoryDown() { h.DownHistory(h.History[h.PromptType]) } // HistorySearchUp fetches the previous history item beginning with the text // in the infobuffer before cursor func (h *InfoPane) HistorySearchUp() { h.SearchUpHistory(h.History[h.PromptType]) } // HistorySearchDown fetches the next history item beginning with the text // in the infobuffer before cursor func (h *InfoPane) HistorySearchDown() { h.SearchDownHistory(h.History[h.PromptType]) } // Autocomplete begins autocompletion func (h *InfoPane) CommandComplete() { b := h.Buf if b.HasSuggestions { b.CycleAutocomplete(true) return } c := b.GetActiveCursor() l := b.LineBytes(0) l = util.SliceStart(l, c.X) args := bytes.Split(l, []byte{' '}) cmd := string(args[0]) if h.PromptType == "Command" { if len(args) == 1 { b.Autocomplete(CommandComplete) } else if action, ok := commands[cmd]; ok { if action.completer != nil { b.Autocomplete(action.completer) } } } else { // by default use filename autocompletion b.Autocomplete(buffer.FileComplete) } } // ExecuteCommand completes the prompt func (h *InfoPane) ExecuteCommand() { if !h.HasYN { h.DonePrompt(false) } } // AbortCommand cancels the prompt func (h *InfoPane) AbortCommand() { h.DonePrompt(true) } // InfoKeyActions contains the list of all possible key actions the infopane could execute var InfoKeyActions = map[string]InfoKeyAction{ "HistoryUp": (*InfoPane).HistoryUp, "HistoryDown": (*InfoPane).HistoryDown, "HistorySearchUp": (*InfoPane).HistorySearchUp, "HistorySearchDown": (*InfoPane).HistorySearchDown, "CommandComplete": (*InfoPane).CommandComplete, "ExecuteCommand": (*InfoPane).ExecuteCommand, "AbortCommand": (*InfoPane).AbortCommand, } zyedidia-micro-6a62575/internal/action/infocomplete.go0000664000175000017510000002103115125206537022344 0ustar nileshnileshpackage action import ( "bytes" "sort" "strings" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/util" "github.com/zyedidia/micro/v2/pkg/highlight" ) // This file is meant (for now) for autocompletion in command mode, not // while coding. This helps micro autocomplete commands and then filenames // for example with `vsplit filename`. // CommandComplete autocompletes commands func CommandComplete(b *buffer.Buffer) ([]string, []string) { c := b.GetActiveCursor() input, argstart := b.GetArg() var suggestions []string for cmd := range commands { if strings.HasPrefix(cmd, input) { suggestions = append(suggestions, cmd) } } sort.Strings(suggestions) completions := make([]string, len(suggestions)) for i := range suggestions { completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart) } return completions, suggestions } // HelpComplete autocompletes help topics func HelpComplete(b *buffer.Buffer) ([]string, []string) { c := b.GetActiveCursor() input, argstart := b.GetArg() var suggestions []string for _, file := range config.ListRuntimeFiles(config.RTHelp) { topic := file.Name() if strings.HasPrefix(topic, input) { suggestions = append(suggestions, topic) } } sort.Strings(suggestions) completions := make([]string, len(suggestions)) for i := range suggestions { completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart) } return completions, suggestions } // colorschemeComplete tab-completes names of colorschemes. // This is just a heper value for OptionValueComplete func colorschemeComplete(input string) (string, []string) { var suggestions []string files := config.ListRuntimeFiles(config.RTColorscheme) for _, f := range files { if strings.HasPrefix(f.Name(), input) { suggestions = append(suggestions, f.Name()) } } var chosen string if len(suggestions) == 1 { chosen = suggestions[0] } return chosen, suggestions } // filetypeComplete autocompletes filetype func filetypeComplete(input string) (string, []string) { var suggestions []string // We cannot match filetypes just by names of syntax files, // since those names may be different from the actual filetype values // specified inside syntax files (e.g. "c++" filetype in cpp.yaml). // So we need to parse filetype values out of those files. for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) { data, err := f.Data() if err != nil { continue } header, err := highlight.MakeHeaderYaml(data) if err != nil { continue } // Prevent duplicated defaults if header.FileType == "off" || header.FileType == "unknown" { continue } if strings.HasPrefix(header.FileType, input) { suggestions = append(suggestions, header.FileType) } } headerLoop: for _, f := range config.ListRuntimeFiles(config.RTSyntaxHeader) { data, err := f.Data() if err != nil { continue } header, err := highlight.MakeHeader(data) if err != nil { continue } for _, v := range suggestions { if v == header.FileType { continue headerLoop } } if strings.HasPrefix(header.FileType, input) { suggestions = append(suggestions, header.FileType) } } if strings.HasPrefix("off", input) { suggestions = append(suggestions, "off") } var chosen string if len(suggestions) == 1 { chosen = suggestions[0] } return chosen, suggestions } // OptionComplete autocompletes options func OptionComplete(b *buffer.Buffer) ([]string, []string) { c := b.GetActiveCursor() input, argstart := b.GetArg() var suggestions []string for option := range config.GlobalSettings { if strings.HasPrefix(option, input) { suggestions = append(suggestions, option) } } // for option := range localSettings { // if strings.HasPrefix(option, input) && !contains(suggestions, option) { // suggestions = append(suggestions, option) // } // } sort.Strings(suggestions) completions := make([]string, len(suggestions)) for i := range suggestions { completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart) } return completions, suggestions } // OptionValueComplete completes values for various options func OptionValueComplete(b *buffer.Buffer) ([]string, []string) { c := b.GetActiveCursor() l := b.LineBytes(c.Y) l = util.SliceStart(l, c.X) input, argstart := b.GetArg() completeValue := false args := bytes.Split(l, []byte{' '}) if len(args) >= 2 { // localSettings := config.DefaultLocalSettings() for option := range config.GlobalSettings { if option == string(args[len(args)-2]) { completeValue = true break } } // for option := range localSettings { // if option == string(args[len(args)-2]) { // completeValue = true // break // } // } } if !completeValue { return OptionComplete(b) } inputOpt := string(args[len(args)-2]) inputOpt = strings.TrimSpace(inputOpt) var suggestions []string // localSettings := config.DefaultLocalSettings() var optionVal any for k, option := range config.GlobalSettings { if k == inputOpt { optionVal = option } } // for k, option := range localSettings { // if k == inputOpt { // optionVal = option // } // } switch optionVal.(type) { case bool: if strings.HasPrefix("on", input) { suggestions = append(suggestions, "on") } else if strings.HasPrefix("true", input) { suggestions = append(suggestions, "true") } if strings.HasPrefix("off", input) { suggestions = append(suggestions, "off") } else if strings.HasPrefix("false", input) { suggestions = append(suggestions, "false") } case string: switch inputOpt { case "colorscheme": _, suggestions = colorschemeComplete(input) case "filetype": _, suggestions = filetypeComplete(input) case "sucmd": if strings.HasPrefix("sudo", input) { suggestions = append(suggestions, "sudo") } if strings.HasPrefix("doas", input) { suggestions = append(suggestions, "doas") } default: if choices, ok := config.OptionChoices[inputOpt]; ok { for _, choice := range choices { if strings.HasPrefix(choice, input) { suggestions = append(suggestions, choice) } } } } } sort.Strings(suggestions) completions := make([]string, len(suggestions)) for i := range suggestions { completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart) } return completions, suggestions } // PluginCmdComplete autocompletes the plugin command func PluginCmdComplete(b *buffer.Buffer) ([]string, []string) { c := b.GetActiveCursor() input, argstart := b.GetArg() var suggestions []string for _, cmd := range PluginCmds { if strings.HasPrefix(cmd, input) { suggestions = append(suggestions, cmd) } } sort.Strings(suggestions) completions := make([]string, len(suggestions)) for i := range suggestions { completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart) } return completions, suggestions } // PluginComplete completes values for the plugin command func PluginComplete(b *buffer.Buffer) ([]string, []string) { c := b.GetActiveCursor() l := b.LineBytes(c.Y) l = util.SliceStart(l, c.X) input, argstart := b.GetArg() completeValue := false args := bytes.Split(l, []byte{' '}) if len(args) >= 2 { for _, cmd := range PluginCmds { if cmd == string(args[len(args)-2]) { completeValue = true break } } } if !completeValue { return PluginCmdComplete(b) } var suggestions []string for _, pl := range config.Plugins { if strings.HasPrefix(pl.Name, input) { suggestions = append(suggestions, pl.Name) } } sort.Strings(suggestions) completions := make([]string, len(suggestions)) for i := range suggestions { completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart) } return completions, suggestions } // PluginNameComplete completes with the names of loaded plugins // func PluginNameComplete(b *buffer.Buffer) ([]string, []string) { // c := b.GetActiveCursor() // input, argstart := buffer.GetArg(b) // // var suggestions []string // for _, pp := range config.GetAllPluginPackages(nil) { // if strings.HasPrefix(pp.Name, input) { // suggestions = append(suggestions, pp.Name) // } // } // // sort.Strings(suggestions) // completions := make([]string, len(suggestions)) // for i := range suggestions { // completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart) // } // return completions, suggestions // } // // MakeCompletion registers a function from a plugin for autocomplete commands // func MakeCompletion(function string) Completion { // pluginCompletions = append(pluginCompletions, LuaFunctionComplete(function)) // return Completion(-len(pluginCompletions)) // } zyedidia-micro-6a62575/internal/action/globals.go0000664000175000017510000000161515125206537021311 0ustar nileshnileshpackage action import "github.com/zyedidia/micro/v2/internal/buffer" // InfoBar is the global info bar. var InfoBar *InfoPane // LogBufPane is a global log buffer. var LogBufPane *BufPane // InitGlobals initializes the log buffer and the info bar func InitGlobals() { InfoBar = NewInfoBar() buffer.LogBuf = buffer.NewBufferFromString("", "", buffer.BTLog) buffer.LogBuf.SetName("Log") } // GetInfoBar returns the infobar pane func GetInfoBar() *InfoPane { return InfoBar } // WriteLog writes a string to the log buffer func WriteLog(s string) { buffer.WriteLog(s) if LogBufPane != nil { LogBufPane.CursorEnd() } } // OpenLogBuf opens the log buffer from the current bufpane // If the current bufpane is a log buffer nothing happens, // otherwise the log buffer is opened in a horizontal split func (h *BufPane) OpenLogBuf() { LogBufPane = h.HSplitBuf(buffer.LogBuf) LogBufPane.CursorEnd() } zyedidia-micro-6a62575/internal/action/events.go0000664000175000017510000000700215125206537021166 0ustar nileshnileshpackage action import ( "bytes" "errors" "fmt" "strings" "github.com/micro-editor/tcell/v2" ) type Event interface { Name() string } // RawEvent is simply an escape code // We allow users to directly bind escape codes // to get around some of a limitations of terminals type RawEvent struct { esc string } func (r RawEvent) Name() string { return r.esc } // KeyEvent is a key event containing a key code, // some possible modifiers (alt, ctrl, etc...) and // a rune if it was simply a character press // Note: to be compatible with tcell events, // for ctrl keys r=code type KeyEvent struct { code tcell.Key mod tcell.ModMask r rune any bool } func metaToAlt(mod tcell.ModMask) tcell.ModMask { if mod&tcell.ModMeta != 0 { mod &= ^tcell.ModMeta mod |= tcell.ModAlt } return mod } func keyEvent(e *tcell.EventKey) KeyEvent { ke := KeyEvent{ code: e.Key(), mod: metaToAlt(e.Modifiers()), } if e.Key() == tcell.KeyRune { ke.r = e.Rune() } return ke } func (k KeyEvent) Name() string { if k.any { return "" } s := "" m := []string{} if k.mod&tcell.ModShift != 0 { m = append(m, "Shift") } if k.mod&tcell.ModAlt != 0 { m = append(m, "Alt") } if k.mod&tcell.ModMeta != 0 { m = append(m, "Meta") } if k.mod&tcell.ModCtrl != 0 { m = append(m, "Ctrl") } ok := false if s, ok = tcell.KeyNames[k.code]; !ok { if k.code == tcell.KeyRune { s = string(k.r) } else { s = fmt.Sprintf("Key[%d]", k.code) } } if len(m) != 0 { if k.mod&tcell.ModCtrl != 0 && strings.HasPrefix(s, "Ctrl-") { s = s[5:] if len(s) == 1 { s = strings.ToLower(s) } } return fmt.Sprintf("%s-%s", strings.Join(m, "-"), s) } return s } // A KeySequence defines a list of consecutive // events. All events in the sequence must be KeyEvents // or MouseEvents. type KeySequenceEvent struct { keys []Event } func (k KeySequenceEvent) Name() string { buf := bytes.Buffer{} for _, e := range k.keys { buf.WriteByte('<') buf.WriteString(e.Name()) buf.WriteByte('>') } return buf.String() } type MouseState int const ( MousePress = iota MouseDrag MouseRelease ) // MouseEvent is a mouse event with a mouse button and // any possible key modifiers type MouseEvent struct { btn tcell.ButtonMask mod tcell.ModMask state MouseState } func (m MouseEvent) Name() string { mod := "" if m.mod&tcell.ModShift != 0 { mod = "Shift-" } if m.mod&tcell.ModAlt != 0 { mod = "Alt-" } if m.mod&tcell.ModMeta != 0 { mod = "Meta-" } if m.mod&tcell.ModCtrl != 0 { mod = "Ctrl-" } state := "" switch m.state { case MouseDrag: state = "Drag" case MouseRelease: state = "Release" } for k, v := range mouseEvents { if v == m.btn { return fmt.Sprintf("%s%s%s", mod, k, state) } } return "" } // ConstructEvent takes a tcell event and returns a micro // event. Note that tcell events can't express certain // micro events such as key sequences. This function is // mostly used for debugging/raw panes or constructing // intermediate micro events while parsing a sequence. func ConstructEvent(event tcell.Event) (Event, error) { switch e := event.(type) { case *tcell.EventKey: return keyEvent(e), nil case *tcell.EventRaw: return RawEvent{ esc: e.EscSeq(), }, nil case *tcell.EventMouse: return MouseEvent{ btn: e.Buttons(), mod: metaToAlt(e.Modifiers()), }, nil } return nil, errors.New("No micro event equivalent") } // A Handler will take a tcell event and execute it // appropriately type Handler interface { HandleEvent(tcell.Event) HandleCommand(string) } zyedidia-micro-6a62575/internal/action/defaults_other.go0000664000175000017510000001371315125206537022700 0ustar nileshnilesh//go:build !darwin // +build !darwin package action var bufdefaults = map[string]string{ "Up": "CursorUp", "Down": "CursorDown", "Right": "CursorRight", "Left": "CursorLeft", "ShiftUp": "SelectUp", "ShiftDown": "SelectDown", "ShiftLeft": "SelectLeft", "ShiftRight": "SelectRight", "CtrlLeft": "WordLeft", "CtrlRight": "WordRight", "AltUp": "MoveLinesUp", "AltDown": "MoveLinesDown", "CtrlShiftRight": "SelectWordRight", "CtrlShiftLeft": "SelectWordLeft", "AltLeft": "StartOfTextToggle", "AltRight": "EndOfLine", "AltShiftLeft": "SelectToStartOfTextToggle", "ShiftHome": "SelectToStartOfTextToggle", "AltShiftRight": "SelectToEndOfLine", "ShiftEnd": "SelectToEndOfLine", "CtrlUp": "CursorStart", "CtrlDown": "CursorEnd", "CtrlShiftUp": "SelectToStart", "CtrlShiftDown": "SelectToEnd", "Alt-{": "ParagraphPrevious", "Alt-}": "ParagraphNext", "Enter": "InsertNewline", "CtrlH": "Backspace", "Backspace": "Backspace", "OldBackspace": "Backspace", "Alt-CtrlH": "DeleteWordLeft", "Alt-Backspace": "DeleteWordLeft", "Tab": "Autocomplete|IndentSelection|InsertTab", "Backtab": "CycleAutocompleteBack|OutdentSelection|OutdentLine", "Ctrl-o": "OpenFile", "Ctrl-s": "Save", "Ctrl-f": "Find", "Alt-F": "FindLiteral", "Ctrl-n": "FindNext", "Ctrl-p": "FindPrevious", "Alt-[": "DiffPrevious|CursorStart", "Alt-]": "DiffNext|CursorEnd", "Ctrl-z": "Undo", "Ctrl-y": "Redo", "Ctrl-c": "Copy|CopyLine", "Ctrl-x": "Cut|CutLine", "Ctrl-k": "CutLine", "Ctrl-d": "Duplicate|DuplicateLine", "Ctrl-v": "Paste", "Ctrl-a": "SelectAll", "Ctrl-t": "AddTab", "Alt-,": "PreviousTab|LastTab", "Alt-.": "NextTab|FirstTab", "Home": "StartOfTextToggle", "End": "EndOfLine", "CtrlHome": "CursorStart", "CtrlEnd": "CursorEnd", "PageUp": "CursorPageUp", "PageDown": "CursorPageDown", "CtrlPageUp": "PreviousTab|LastTab", "CtrlPageDown": "NextTab|FirstTab", "ShiftPageUp": "SelectPageUp", "ShiftPageDown": "SelectPageDown", "Ctrl-g": "ToggleHelp", "Alt-g": "ToggleKeyMenu", "Ctrl-r": "ToggleRuler", "Ctrl-l": "command-edit:goto ", "Delete": "Delete", "Ctrl-b": "ShellMode", "Ctrl-q": "Quit", "Ctrl-e": "CommandMode", "Ctrl-w": "NextSplit|FirstSplit", "Ctrl-u": "ToggleMacro", "Ctrl-j": "PlayMacro", "Insert": "ToggleOverwriteMode", // Emacs-style keybindings "Alt-f": "WordRight", "Alt-b": "WordLeft", "Alt-a": "StartOfText", "Alt-e": "EndOfLine", // "Alt-p": "CursorUp", // "Alt-n": "CursorDown", // Integration with file managers "F2": "Save", "F3": "Find", "F4": "Quit", "F7": "Find", "F10": "Quit", "Esc": "Escape,Deselect,ClearInfo,RemoveAllMultiCursors,UnhighlightSearch", // Mouse bindings "MouseWheelUp": "ScrollUp", "MouseWheelDown": "ScrollDown", "MouseLeft": "MousePress", "MouseLeftDrag": "MouseDrag", "MouseLeftRelease": "MouseRelease", "MouseMiddle": "PastePrimary", "Ctrl-MouseLeft": "MouseMultiCursor", "Alt-n": "SpawnMultiCursor", "Alt-m": "SpawnMultiCursorSelect", "AltShiftUp": "SpawnMultiCursorUp", "AltShiftDown": "SpawnMultiCursorDown", "Alt-p": "RemoveMultiCursor", "Alt-c": "RemoveAllMultiCursors", "Alt-x": "SkipMultiCursor", } var infodefaults = map[string]string{ "Up": "HistoryUp", "Down": "HistoryDown", "Right": "CursorRight", "Left": "CursorLeft", "ShiftUp": "SelectUp", "ShiftDown": "SelectDown", "ShiftLeft": "SelectLeft", "ShiftRight": "SelectRight", "AltLeft": "StartOfTextToggle", "AltRight": "EndOfLine", "AltUp": "CursorStart", "AltDown": "CursorEnd", "AltShiftRight": "SelectWordRight", "AltShiftLeft": "SelectWordLeft", "CtrlLeft": "WordLeft", "CtrlRight": "WordRight", "CtrlShiftLeft": "SelectToStartOfTextToggle", "ShiftHome": "SelectToStartOfTextToggle", "CtrlShiftRight": "SelectToEndOfLine", "ShiftEnd": "SelectToEndOfLine", "CtrlUp": "CursorStart", "CtrlDown": "CursorEnd", "CtrlShiftUp": "SelectToStart", "CtrlShiftDown": "SelectToEnd", "Enter": "ExecuteCommand", "CtrlH": "Backspace", "Backspace": "Backspace", "OldBackspace": "Backspace", "Alt-CtrlH": "DeleteWordLeft", "Alt-Backspace": "DeleteWordLeft", "Tab": "CommandComplete", "Backtab": "CycleAutocompleteBack", "Ctrl-z": "Undo", "Ctrl-y": "Redo", "Ctrl-c": "Copy|CopyLine", "Ctrl-x": "Cut|CutLine", "Ctrl-k": "CutLine", "Ctrl-v": "Paste", "Home": "StartOfTextToggle", "End": "EndOfLine", "CtrlHome": "CursorStart", "CtrlEnd": "CursorEnd", "Delete": "Delete", "Ctrl-q": "AbortCommand", "Ctrl-e": "EndOfLine", "Ctrl-a": "StartOfLine", "Ctrl-w": "DeleteWordLeft", "Insert": "ToggleOverwriteMode", "Ctrl-b": "WordLeft", "Ctrl-f": "WordRight", "Ctrl-d": "DeleteWordLeft", "Ctrl-m": "ExecuteCommand", "Ctrl-n": "HistoryDown", "Ctrl-p": "HistoryUp", "Ctrl-u": "SelectToStart", // Emacs-style keybindings "Alt-f": "WordRight", "Alt-b": "WordLeft", "Alt-a": "StartOfText", "Alt-e": "EndOfLine", // Integration with file managers "F10": "AbortCommand", "Esc": "AbortCommand", // Mouse bindings "MouseWheelUp": "HistoryUp", "MouseWheelDown": "HistoryDown", "MouseLeft": "MousePress", "MouseLeftDrag": "MouseDrag", "MouseLeftRelease": "MouseRelease", "MouseMiddle": "PastePrimary", } zyedidia-micro-6a62575/internal/action/defaults_darwin.go0000664000175000017510000001364515125206537023047 0ustar nileshnileshpackage action var bufdefaults = map[string]string{ "Up": "CursorUp", "Down": "CursorDown", "Right": "CursorRight", "Left": "CursorLeft", "ShiftUp": "SelectUp", "ShiftDown": "SelectDown", "ShiftLeft": "SelectLeft", "ShiftRight": "SelectRight", "AltLeft": "WordLeft", "AltRight": "WordRight", "AltUp": "MoveLinesUp", "AltDown": "MoveLinesDown", "AltShiftRight": "SelectWordRight", "AltShiftLeft": "SelectWordLeft", "CtrlLeft": "StartOfTextToggle", "CtrlRight": "EndOfLine", "CtrlShiftLeft": "SelectToStartOfTextToggle", "ShiftHome": "SelectToStartOfTextToggle", "CtrlShiftRight": "SelectToEndOfLine", "ShiftEnd": "SelectToEndOfLine", "CtrlUp": "CursorStart", "CtrlDown": "CursorEnd", "CtrlShiftUp": "SelectToStart", "CtrlShiftDown": "SelectToEnd", "Alt-{": "ParagraphPrevious", "Alt-}": "ParagraphNext", "Enter": "InsertNewline", "CtrlH": "Backspace", "Backspace": "Backspace", "OldBackspace": "Backspace", "Alt-CtrlH": "DeleteWordLeft", "Alt-Backspace": "DeleteWordLeft", "Tab": "Autocomplete|IndentSelection|InsertTab", "Backtab": "CycleAutocompleteBack|OutdentSelection|OutdentLine", "Ctrl-o": "OpenFile", "Ctrl-s": "Save", "Ctrl-f": "Find", "Alt-F": "FindLiteral", "Ctrl-n": "FindNext", "Ctrl-p": "FindPrevious", "Alt-[": "DiffPrevious|CursorStart", "Alt-]": "DiffNext|CursorEnd", "Ctrl-z": "Undo", "Ctrl-y": "Redo", "Ctrl-c": "Copy|CopyLine", "Ctrl-x": "Cut|CutLine", "Ctrl-k": "CutLine", "Ctrl-d": "Duplicate|DuplicateLine", "Ctrl-v": "Paste", "Ctrl-a": "SelectAll", "Ctrl-t": "AddTab", "Alt-,": "PreviousTab|LastTab", "Alt-.": "NextTab|FirstTab", "Home": "StartOfTextToggle", "End": "EndOfLine", "CtrlHome": "CursorStart", "CtrlEnd": "CursorEnd", "PageUp": "CursorPageUp", "PageDown": "CursorPageDown", "CtrlPageUp": "PreviousTab|LastTab", "CtrlPageDown": "NextTab|FirstTab", "ShiftPageUp": "SelectPageUp", "ShiftPageDown": "SelectPageDown", "Ctrl-g": "ToggleHelp", "Alt-g": "ToggleKeyMenu", "Ctrl-r": "ToggleRuler", "Ctrl-l": "command-edit:goto ", "Delete": "Delete", "Ctrl-b": "ShellMode", "Ctrl-q": "Quit", "Ctrl-e": "CommandMode", "Ctrl-w": "NextSplit|FirstSplit", "Ctrl-u": "ToggleMacro", "Ctrl-j": "PlayMacro", "Insert": "ToggleOverwriteMode", // Emacs-style keybindings "Alt-f": "WordRight", "Alt-b": "WordLeft", "Alt-a": "StartOfText", "Alt-e": "EndOfLine", // "Alt-p": "CursorUp", // "Alt-n": "CursorDown", // Integration with file managers "F2": "Save", "F3": "Find", "F4": "Quit", "F7": "Find", "F10": "Quit", "Esc": "Escape,Deselect,ClearInfo,RemoveAllMultiCursors,UnhighlightSearch", // Mouse bindings "MouseWheelUp": "ScrollUp", "MouseWheelDown": "ScrollDown", "MouseLeft": "MousePress", "MouseLeftDrag": "MouseDrag", "MouseLeftRelease": "MouseRelease", "MouseMiddle": "PastePrimary", "Ctrl-MouseLeft": "MouseMultiCursor", "Alt-n": "SpawnMultiCursor", "AltShiftUp": "SpawnMultiCursorUp", "AltShiftDown": "SpawnMultiCursorDown", "Alt-m": "SpawnMultiCursorSelect", "Alt-p": "RemoveMultiCursor", "Alt-c": "RemoveAllMultiCursors", "Alt-x": "SkipMultiCursor", } var infodefaults = map[string]string{ "Up": "HistoryUp", "Down": "HistoryDown", "Right": "CursorRight", "Left": "CursorLeft", "ShiftUp": "SelectUp", "ShiftDown": "SelectDown", "ShiftLeft": "SelectLeft", "ShiftRight": "SelectRight", "AltLeft": "WordLeft", "AltRight": "WordRight", "AltUp": "CursorStart", "AltDown": "CursorEnd", "AltShiftRight": "SelectWordRight", "AltShiftLeft": "SelectWordLeft", "CtrlLeft": "StartOfTextToggle", "CtrlRight": "EndOfLine", "CtrlShiftLeft": "SelectToStartOfTextToggle", "ShiftHome": "SelectToStartOfTextToggle", "CtrlShiftRight": "SelectToEndOfLine", "ShiftEnd": "SelectToEndOfLine", "CtrlUp": "CursorStart", "CtrlDown": "CursorEnd", "CtrlShiftUp": "SelectToStart", "CtrlShiftDown": "SelectToEnd", "Enter": "ExecuteCommand", "CtrlH": "Backspace", "Backspace": "Backspace", "OldBackspace": "Backspace", "Alt-CtrlH": "DeleteWordLeft", "Alt-Backspace": "DeleteWordLeft", "Tab": "CommandComplete", "Backtab": "CycleAutocompleteBack", "Ctrl-z": "Undo", "Ctrl-y": "Redo", "Ctrl-c": "Copy|CopyLine", "Ctrl-x": "Cut|CutLine", "Ctrl-k": "CutLine", "Ctrl-v": "Paste", "Home": "StartOfTextToggle", "End": "EndOfLine", "CtrlHome": "CursorStart", "CtrlEnd": "CursorEnd", "Delete": "Delete", "Ctrl-q": "AbortCommand", "Ctrl-e": "EndOfLine", "Ctrl-a": "StartOfLine", "Ctrl-w": "DeleteWordLeft", "Insert": "ToggleOverwriteMode", "Ctrl-b": "WordLeft", "Ctrl-f": "WordRight", "Ctrl-d": "DeleteWordLeft", "Ctrl-m": "ExecuteCommand", "Ctrl-n": "HistoryDown", "Ctrl-p": "HistoryUp", "Ctrl-u": "SelectToStart", // Emacs-style keybindings "Alt-f": "WordRight", "Alt-b": "WordLeft", "Alt-a": "StartOfText", "Alt-e": "EndOfLine", // Integration with file managers "F10": "AbortCommand", "Esc": "AbortCommand", // Mouse bindings "MouseWheelUp": "HistoryUp", "MouseWheelDown": "HistoryDown", "MouseLeft": "MousePress", "MouseLeftDrag": "MouseDrag", "MouseLeftRelease": "MouseRelease", "MouseMiddle": "PastePrimary", } zyedidia-micro-6a62575/internal/action/defaults.go0000664000175000017510000000072415125206537021475 0ustar nileshnileshpackage action var termdefaults = map[string]string{ "": "Exit", "": "CommandMode", "": "NextSplit|FirstSplit", } // DefaultBindings returns a map containing micro's default keybindings func DefaultBindings(pane string) map[string]string { switch pane { case "command": return infodefaults case "buffer": return bufdefaults case "terminal": return termdefaults default: return map[string]string{} } } zyedidia-micro-6a62575/internal/action/command.go0000664000175000017510000007154015125206537021310 0ustar nileshnileshpackage action import ( "bytes" "errors" "fmt" "os" "os/exec" "path/filepath" "reflect" "regexp" "strconv" "strings" shellquote "github.com/kballard/go-shellquote" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/clipboard" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/shell" "github.com/zyedidia/micro/v2/internal/util" ) // A Command contains information about how to execute a command // It has the action for that command as well as a completer function type Command struct { action func(*BufPane, []string) completer buffer.Completer } var commands map[string]Command func InitCommands() { commands = map[string]Command{ "set": {(*BufPane).SetCmd, OptionValueComplete}, "setlocal": {(*BufPane).SetLocalCmd, OptionValueComplete}, "toggle": {(*BufPane).ToggleCmd, OptionValueComplete}, "togglelocal": {(*BufPane).ToggleLocalCmd, OptionValueComplete}, "reset": {(*BufPane).ResetCmd, OptionValueComplete}, "show": {(*BufPane).ShowCmd, OptionComplete}, "showkey": {(*BufPane).ShowKeyCmd, nil}, "run": {(*BufPane).RunCmd, nil}, "bind": {(*BufPane).BindCmd, nil}, "unbind": {(*BufPane).UnbindCmd, nil}, "quit": {(*BufPane).QuitCmd, nil}, "goto": {(*BufPane).GotoCmd, nil}, "jump": {(*BufPane).JumpCmd, nil}, "save": {(*BufPane).SaveCmd, nil}, "replace": {(*BufPane).ReplaceCmd, nil}, "replaceall": {(*BufPane).ReplaceAllCmd, nil}, "vsplit": {(*BufPane).VSplitCmd, buffer.FileComplete}, "hsplit": {(*BufPane).HSplitCmd, buffer.FileComplete}, "tab": {(*BufPane).NewTabCmd, buffer.FileComplete}, "help": {(*BufPane).HelpCmd, HelpComplete}, "eval": {(*BufPane).EvalCmd, nil}, "log": {(*BufPane).ToggleLogCmd, nil}, "plugin": {(*BufPane).PluginCmd, PluginComplete}, "reload": {(*BufPane).ReloadCmd, nil}, "reopen": {(*BufPane).ReopenCmd, nil}, "cd": {(*BufPane).CdCmd, buffer.FileComplete}, "pwd": {(*BufPane).PwdCmd, nil}, "open": {(*BufPane).OpenCmd, buffer.FileComplete}, "tabmove": {(*BufPane).TabMoveCmd, nil}, "tabswitch": {(*BufPane).TabSwitchCmd, nil}, "term": {(*BufPane).TermCmd, nil}, "memusage": {(*BufPane).MemUsageCmd, nil}, "retab": {(*BufPane).RetabCmd, nil}, "raw": {(*BufPane).RawCmd, nil}, "textfilter": {(*BufPane).TextFilterCmd, nil}, } } // MakeCommand is a function to easily create new commands // This can be called by plugins in Lua so that plugins can define their own commands func MakeCommand(name string, action func(bp *BufPane, args []string), completer buffer.Completer) { if action != nil { commands[name] = Command{action, completer} } } // CommandEditAction returns a bindable function that opens a prompt with // the given string and executes the command when the user presses // enter func CommandEditAction(prompt string) BufKeyAction { return func(h *BufPane) bool { InfoBar.Prompt("> ", prompt, "Command", nil, func(resp string, canceled bool) { if !canceled { MainTab().CurPane().HandleCommand(resp) } }) return false } } // CommandAction returns a bindable function which executes the // given command func CommandAction(cmd string) BufKeyAction { return func(h *BufPane) bool { MainTab().CurPane().HandleCommand(cmd) return false } } var PluginCmds = []string{"install", "remove", "update", "available", "list", "search"} // PluginCmd installs, removes, updates, lists, or searches for given plugins func (h *BufPane) PluginCmd(args []string) { if len(args) < 1 { InfoBar.Error("Not enough arguments") return } if h.Buf.Type != buffer.BTLog { h.OpenLogBuf() } config.PluginCommand(buffer.LogBuf, args[0], args[1:]) } // RetabCmd changes all spaces to tabs or all tabs to spaces // depending on the user's settings func (h *BufPane) RetabCmd(args []string) { h.Buf.Retab() } // RawCmd opens a new raw view which displays the escape sequences micro // is receiving in real-time func (h *BufPane) RawCmd(args []string) { width, height := screen.Screen.Size() iOffset := config.GetInfoBarOffset() tp := NewTabFromPane(0, 0, width, height-iOffset, NewRawPane(nil)) Tabs.AddTab(tp) Tabs.SetActive(len(Tabs.List) - 1) } // TextFilterCmd filters the selection through the command. // Selection goes to the command input. // On successful run command output replaces the current selection. func (h *BufPane) TextFilterCmd(args []string) { if len(args) == 0 { InfoBar.Error("usage: textfilter arguments") return } for _, c := range h.Buf.GetCursors() { sel := c.GetSelection() if len(sel) == 0 { c.SelectWord() sel = c.GetSelection() } var bout, berr bytes.Buffer cmd := exec.Command(args[0], args[1:]...) cmd.Stdin = strings.NewReader(string(sel)) cmd.Stderr = &berr cmd.Stdout = &bout err := cmd.Run() if err != nil { InfoBar.Error(err.Error() + " " + berr.String()) return } c.DeleteSelection() h.Buf.Insert(c.Loc, bout.String()) } } // TabMoveCmd moves the current tab to a given index (starts at 1). The // displaced tabs are moved up. func (h *BufPane) TabMoveCmd(args []string) { if len(args) <= 0 { InfoBar.Error("Not enough arguments: provide an index, starting at 1") return } if len(args[0]) <= 0 { InfoBar.Error("Invalid argument: empty string") return } num, err := strconv.Atoi(args[0]) if err != nil { InfoBar.Error("Invalid argument: ", err) return } // Preserve sign for relative move, if one exists var shiftDirection byte if strings.Contains("-+", string([]byte{args[0][0]})) { shiftDirection = args[0][0] } // Relative positions -> absolute positions idxFrom := Tabs.Active() idxTo := 0 offset := util.Abs(num) if shiftDirection == '-' { idxTo = idxFrom - offset } else if shiftDirection == '+' { idxTo = idxFrom + offset } else { idxTo = offset - 1 } // Restrain position to within the valid range idxTo = util.Clamp(idxTo, 0, len(Tabs.List)-1) activeTab := Tabs.List[idxFrom] Tabs.RemoveTab(activeTab.Panes[0].ID()) Tabs.List = append(Tabs.List, nil) copy(Tabs.List[idxTo+1:], Tabs.List[idxTo:]) Tabs.List[idxTo] = activeTab Tabs.Resize() Tabs.UpdateNames() Tabs.SetActive(idxTo) // InfoBar.Message(fmt.Sprintf("Moved tab from slot %d to %d", idxFrom+1, idxTo+1)) } // TabSwitchCmd switches to a given tab either by name or by number func (h *BufPane) TabSwitchCmd(args []string) { if len(args) > 0 { num, err := strconv.Atoi(args[0]) if err != nil { // Check for tab with this name found := false for i, t := range Tabs.List { if t.Panes[t.active].Name() == args[0] { Tabs.SetActive(i) found = true } } if !found { InfoBar.Error("Could not find tab: ", err) } } else { num-- if num >= 0 && num < len(Tabs.List) { Tabs.SetActive(num) } else { InfoBar.Error("Invalid tab index") } } } } // CdCmd changes the current working directory func (h *BufPane) CdCmd(args []string) { if len(args) > 0 { path, err := util.ReplaceHome(args[0]) if err != nil { InfoBar.Error(err) return } err = os.Chdir(path) if err != nil { InfoBar.Error(err) return } wd, _ := os.Getwd() for _, b := range buffer.OpenBuffers { if len(b.Path) > 0 { b.Path, _ = util.MakeRelative(b.AbsPath, wd) if p, _ := filepath.Abs(b.Path); !strings.Contains(p, wd) { b.Path = b.AbsPath } } } } } // MemUsageCmd prints micro's memory usage // Alloc shows how many bytes are currently in use // Sys shows how many bytes have been requested from the operating system // NumGC shows how many times the GC has been run // Note that Go commonly reserves more memory from the OS than is currently in-use/required // Additionally, even if Go returns memory to the OS, the OS does not always claim it because // there may be plenty of memory to spare func (h *BufPane) MemUsageCmd(args []string) { InfoBar.Message(util.GetMemStats()) } // PwdCmd prints the current working directory func (h *BufPane) PwdCmd(args []string) { wd, err := os.Getwd() if err != nil { InfoBar.Message(err.Error()) } else { InfoBar.Message(wd) } } // OpenCmd opens a new buffer with a given filename func (h *BufPane) OpenCmd(args []string) { if len(args) > 0 { filename := args[0] // the filename might or might not be quoted, so unquote first then join the strings. args, err := shellquote.Split(filename) if err != nil { InfoBar.Error("Error parsing args ", err) return } if len(args) == 0 { return } filename = strings.Join(args, " ") open := func() { b, err := buffer.NewBufferFromFile(filename, buffer.BTDefault) if err != nil { InfoBar.Error(err) return } h.OpenBuffer(b) } if h.Buf.Modified() && !h.Buf.Shared() { h.closePrompt("Save", open) } else { open() } } else { InfoBar.Error("No filename") } } // ToggleLogCmd toggles the log view func (h *BufPane) ToggleLogCmd(args []string) { if h.Buf.Type != buffer.BTLog { h.OpenLogBuf() } else { h.Quit() } } // ReloadCmd reloads all files (syntax files, colorschemes, plugins...) func (h *BufPane) ReloadCmd(args []string) { reloadRuntime(true) } // ReloadConfig reloads only the configuration func ReloadConfig() { reloadRuntime(false) } func reloadRuntime(reloadPlugins bool) { if reloadPlugins { err := config.RunPluginFn("deinit") if err != nil { screen.TermMessage(err) } } config.InitRuntimeFiles(true) if reloadPlugins { config.InitPlugins() } err := config.ReadSettings() if err != nil { screen.TermMessage(err) } else { parsedSettings := config.ParsedSettings() defaultSettings := config.DefaultAllSettings() for k := range defaultSettings { if _, ok := config.VolatileSettings[k]; ok { // reload should not override volatile settings continue } if _, ok := parsedSettings[k]; ok { err = doSetGlobalOptionNative(k, parsedSettings[k]) } else { err = doSetGlobalOptionNative(k, defaultSettings[k]) } if err != nil { screen.TermMessage(err) } } } if reloadPlugins { err = config.LoadAllPlugins() if err != nil { screen.TermMessage(err) } } InitBindings() InitCommands() if reloadPlugins { err = config.RunPluginFn("preinit") if err != nil { screen.TermMessage(err) } err = config.RunPluginFn("init") if err != nil { screen.TermMessage(err) } err = config.RunPluginFn("postinit") if err != nil { screen.TermMessage(err) } } err = config.InitColorscheme() if err != nil { screen.TermMessage(err) } for _, b := range buffer.OpenBuffers { b.ReloadSettings(true) } } // ReopenCmd reopens the buffer (reload from disk) func (h *BufPane) ReopenCmd(args []string) { if h.Buf.Modified() { InfoBar.YNPrompt("Save file before reopen?", func(yes, canceled bool) { if !canceled && yes { h.Save() h.ReOpen() } else if !canceled { h.ReOpen() } }) } else { h.ReOpen() } } func (h *BufPane) openHelp(page string, hsplit bool, forceSplit bool) error { if data, err := config.FindRuntimeFile(config.RTHelp, page).Data(); err != nil { return errors.New(fmt.Sprintf("Unable to load help text for %s: %v", page, err)) } else { helpBuffer := buffer.NewBufferFromString(string(data), page+".md", buffer.BTHelp) helpBuffer.SetName("Help " + page) helpBuffer.SetOptionNative("hltaberrors", false) helpBuffer.SetOptionNative("hltrailingws", false) if h.Buf.Type == buffer.BTHelp && !forceSplit { h.OpenBuffer(helpBuffer) } else if hsplit { h.HSplitBuf(helpBuffer) } else { h.VSplitBuf(helpBuffer) } } return nil } // HelpCmd tries to open the given help page according to the split type // configured with the "helpsplit" option. It can be overriden by the optional // arguments "-vpslit" or "-hsplit". In case more than one help page is given // as argument then it opens all of them with the defined split type. func (h *BufPane) HelpCmd(args []string) { hsplit := config.GlobalSettings["helpsplit"] == "hsplit" if len(args) < 1 { // Open the default help if the user just typed "> help" h.openHelp("help", hsplit, false) } else { var topics []string forceSplit := false const errSplit = "hsplit and vsplit are not allowed at the same time" for _, arg := range args { switch arg { case "-vsplit": if forceSplit { InfoBar.Error(errSplit) return } hsplit = false forceSplit = true case "-hsplit": if forceSplit { InfoBar.Error(errSplit) return } hsplit = true forceSplit = true default: topics = append(topics, arg) } } if len(topics) < 1 { // Do the same as without arg h.openHelp("help", hsplit, forceSplit) return } if len(topics) > 1 { forceSplit = true } for _, topic := range topics { if config.FindRuntimeFile(config.RTHelp, topic) != nil { err := h.openHelp(topic, hsplit, forceSplit) if err != nil { InfoBar.Error(err) } } else { InfoBar.Error("Sorry, no help for ", topic) } } } } // VSplitCmd opens one or more vertical splits with the files given as arguments // If no file is given, it opens an empty buffer in a new split func (h *BufPane) VSplitCmd(args []string) { if len(args) == 0 { // Open an empty vertical split h.VSplitAction() return } for _, a := range args { buf, err := buffer.NewBufferFromFile(a, buffer.BTDefault) if err != nil { InfoBar.Error(err) return } h.VSplitBuf(buf) } } // HSplitCmd opens one or more horizontal splits with the files given as arguments // If no file is given, it opens an empty buffer in a new split func (h *BufPane) HSplitCmd(args []string) { if len(args) == 0 { // Open an empty horizontal split h.HSplitAction() return } for _, a := range args { buf, err := buffer.NewBufferFromFile(a, buffer.BTDefault) if err != nil { InfoBar.Error(err) return } h.HSplitBuf(buf) } } // EvalCmd evaluates a lua expression func (h *BufPane) EvalCmd(args []string) { InfoBar.Error("Eval unsupported") } // NewTabCmd opens one or more tabs with the files given as arguments // If no file is given, it opens an empty buffer in a new tab func (h *BufPane) NewTabCmd(args []string) { width, height := screen.Screen.Size() iOffset := config.GetInfoBarOffset() if len(args) > 0 { for _, a := range args { b, err := buffer.NewBufferFromFile(a, buffer.BTDefault) if err != nil { InfoBar.Error(err) return } tp := NewTabFromBuffer(0, 0, width, height-1-iOffset, b) Tabs.AddTab(tp) Tabs.SetActive(len(Tabs.List) - 1) } } else { b := buffer.NewBufferFromString("", "", buffer.BTDefault) tp := NewTabFromBuffer(0, 0, width, height-iOffset, b) Tabs.AddTab(tp) Tabs.SetActive(len(Tabs.List) - 1) } } func doSetGlobalOptionNative(option string, nativeValue any) error { if reflect.DeepEqual(config.GlobalSettings[option], nativeValue) { return nil } config.GlobalSettings[option] = nativeValue config.ModifiedSettings[option] = true delete(config.VolatileSettings, option) if option == "colorscheme" { // LoadSyntaxFiles() config.InitColorscheme() for _, b := range buffer.OpenBuffers { b.UpdateRules() } } else if option == "infobar" || option == "keymenu" { Tabs.Resize() } else if option == "mouse" { if !nativeValue.(bool) { screen.Screen.DisableMouse() } else { screen.Screen.EnableMouse() } } else if option == "autosave" { if nativeValue.(float64) > 0 { config.SetAutoTime(nativeValue.(float64)) } else { config.SetAutoTime(0) } } else if option == "paste" { screen.Screen.SetPaste(nativeValue.(bool)) } else if option == "clipboard" { m := clipboard.SetMethod(nativeValue.(string)) err := clipboard.Initialize(m) if err != nil { return err } } else { for _, pl := range config.Plugins { if option == pl.Name { if nativeValue.(bool) && !pl.Loaded { pl.Load() _, err := pl.Call("init") if err != nil && err != config.ErrNoSuchFunction { screen.TermMessage(err) } } else if !nativeValue.(bool) && pl.Loaded { _, err := pl.Call("deinit") if err != nil && err != config.ErrNoSuchFunction { screen.TermMessage(err) } } } } } return nil } func SetGlobalOptionNative(option string, nativeValue any, writeToFile bool) error { if err := config.OptionIsValid(option, nativeValue); err != nil { return err } // check for local option first... for _, s := range config.LocalSettings { if s == option { return MainTab().CurPane().Buf.SetOptionNative(option, nativeValue) } } // ...if it's not local continue with the globals... if err := doSetGlobalOptionNative(option, nativeValue); err != nil { return err } // ...at last check the buffer locals for _, b := range buffer.OpenBuffers { b.DoSetOptionNative(option, nativeValue) delete(b.LocalSettings, option) } if !writeToFile { return nil } err := config.WriteSettings(filepath.Join(config.ConfigDir, "settings.json")) if err != nil { if errors.Is(err, util.ErrOverwrite) { screen.TermMessage(err) err = errors.Unwrap(err) } return err } return nil } func SetGlobalOption(option, value string, writeToFile bool) error { if _, ok := config.GlobalSettings[option]; !ok { return config.ErrInvalidOption } nativeValue, err := config.GetNativeValue(option, value) if err != nil { return err } return SetGlobalOptionNative(option, nativeValue, writeToFile) } func SetGlobalOptionNativePlug(option string, nativeValue any) error { return SetGlobalOptionNative(option, nativeValue, false) } func SetGlobalOptionPlug(option, value string) error { return SetGlobalOption(option, value, false) } // ResetCmd resets a setting to its default value func (h *BufPane) ResetCmd(args []string) { if len(args) < 1 { InfoBar.Error("Not enough arguments") return } option := args[0] defaults := config.DefaultAllSettings() if _, ok := defaults[option]; ok { SetGlobalOptionNative(option, defaults[option], true) return } InfoBar.Error(config.ErrInvalidOption) } // SetCmd sets an option func (h *BufPane) SetCmd(args []string) { if len(args) < 2 { InfoBar.Error("Not enough arguments") return } option := args[0] value := args[1] err := SetGlobalOption(option, value, true) if err == config.ErrInvalidOption { err := h.Buf.SetOption(option, value) if err != nil { InfoBar.Error(err) } } else if err != nil { InfoBar.Error(err) } } // SetLocalCmd sets an option local to the buffer func (h *BufPane) SetLocalCmd(args []string) { if len(args) < 2 { InfoBar.Error("Not enough arguments") return } option := args[0] value := args[1] err := h.Buf.SetOption(option, value) if err != nil { InfoBar.Error(err) } } func (h *BufPane) toggleOption(option string, local bool) error { var curVal, newVal any if local { curVal = h.Buf.Settings[option] } else { curVal = config.GetGlobalOption(option) } if curVal == nil { return config.ErrInvalidOption } if choices, ok := config.OptionChoices[option]; ok && len(choices) == 2 { if curVal == choices[0] { newVal = choices[1] } else { newVal = choices[0] } } else if curValBool, ok := curVal.(bool); ok { newVal = !curValBool } else { return config.ErrOptNotToggleable } if local { if err := h.Buf.SetOptionNative(option, newVal); err != nil { return err } } else { if err := SetGlobalOptionNative(option, newVal, true); err != nil { return err } } return nil } // ToggleCmd toggles a toggleable option func (h *BufPane) ToggleCmd(args []string) { if len(args) < 1 { InfoBar.Error("Not enough arguments: provide a toggleable option") return } if err := h.toggleOption(args[0], false); err != nil { InfoBar.Error(err) } } // ToggleCmd toggles a toggleable option local to the buffer func (h *BufPane) ToggleLocalCmd(args []string) { if len(args) < 1 { InfoBar.Error("Not enough arguments: provide a toggleable option") return } if err := h.toggleOption(args[0], true); err != nil { InfoBar.Error(err) } } // ShowCmd shows the value of the given option func (h *BufPane) ShowCmd(args []string) { if len(args) < 1 { InfoBar.Error("Please provide an option to show") return } var option any if opt, ok := h.Buf.Settings[args[0]]; ok { option = opt } else if opt, ok := config.GlobalSettings[args[0]]; ok { option = opt } if option == nil { InfoBar.Error(args[0], " is not a valid option") return } InfoBar.Message(option) } func parseKeyArg(arg string) string { // If this is a raw escape sequence, convert it to its raw byte form return strings.ReplaceAll(arg, "\\x1b", "\x1b") } // ShowKeyCmd displays the action that a key is bound to func (h *BufPane) ShowKeyCmd(args []string) { if len(args) < 1 { InfoBar.Error("Please provide a key to show") return } event, err := findEvent(parseKeyArg(args[0])) if err != nil { InfoBar.Error(err) return } if action, ok := config.Bindings["buffer"][event.Name()]; ok { InfoBar.Message(action) } else { InfoBar.Message(args[0], " has no binding") } } // BindCmd creates a new keybinding func (h *BufPane) BindCmd(args []string) { if len(args) < 2 { InfoBar.Error("Not enough arguments") return } _, err := TryBindKey(parseKeyArg(args[0]), args[1], true, true) if err != nil { if errors.Is(err, util.ErrOverwrite) { screen.TermMessage(err) } else { InfoBar.Error(err) } } } // UnbindCmd binds a key to its default action func (h *BufPane) UnbindCmd(args []string) { if len(args) < 1 { InfoBar.Error("Not enough arguments") return } err := UnbindKey(parseKeyArg(args[0])) if err != nil { if errors.Is(err, util.ErrOverwrite) { screen.TermMessage(err) } else { InfoBar.Error(err) } } } // RunCmd runs a shell command in the background func (h *BufPane) RunCmd(args []string) { runf, err := shell.RunBackgroundShell(shellquote.Join(args...)) if err != nil { InfoBar.Error(err) } else { go func() { InfoBar.Message(runf()) screen.Redraw() }() } } // QuitCmd closes the main view func (h *BufPane) QuitCmd(args []string) { h.Quit() } // GotoCmd is a command that will send the cursor to a certain // position in the buffer // For example: `goto line`, or `goto line:col` func (h *BufPane) GotoCmd(args []string) { line, col, err := h.parseLineCol(args) if err != nil { InfoBar.Error(err) return } if line < 0 { line = h.Buf.LinesNum() + 1 + line } line = util.Clamp(line-1, 0, h.Buf.LinesNum()-1) col = util.Clamp(col-1, 0, util.CharacterCount(h.Buf.LineBytes(line))) h.RemoveAllMultiCursors() h.Cursor.Deselect(true) h.GotoLoc(buffer.Loc{col, line}) } // JumpCmd is a command that will send the cursor to a certain relative // position in the buffer // For example: `jump line`, `jump -line`, or `jump -line:col` func (h *BufPane) JumpCmd(args []string) { line, col, err := h.parseLineCol(args) if err != nil { InfoBar.Error(err) return } line = h.Buf.GetActiveCursor().Y + 1 + line line = util.Clamp(line-1, 0, h.Buf.LinesNum()-1) col = util.Clamp(col-1, 0, util.CharacterCount(h.Buf.LineBytes(line))) h.RemoveAllMultiCursors() h.Cursor.Deselect(true) h.GotoLoc(buffer.Loc{col, line}) } // parseLineCol is a helper to parse the input of GotoCmd and JumpCmd func (h *BufPane) parseLineCol(args []string) (line int, col int, err error) { if len(args) <= 0 { return 0, 0, errors.New("Not enough arguments") } line, col = 0, 0 if strings.Contains(args[0], ":") { parts := strings.SplitN(args[0], ":", 2) line, err = strconv.Atoi(parts[0]) if err != nil { return 0, 0, err } col, err = strconv.Atoi(parts[1]) if err != nil { return 0, 0, err } } else { line, err = strconv.Atoi(args[0]) if err != nil { return 0, 0, err } } return line, col, nil } // SaveCmd saves the buffer optionally with an argument file name func (h *BufPane) SaveCmd(args []string) { if len(args) == 0 { h.Save() } else { h.saveBufToFile(args[0], "SaveAs", nil) } } // ReplaceCmd runs search and replace func (h *BufPane) ReplaceCmd(args []string) { if len(args) < 2 || len(args) > 4 { // We need to find both a search and replace expression InfoBar.Error("Invalid replace statement: " + strings.Join(args, " ")) return } all := false noRegex := false foundSearch := false foundReplace := false var search string var replaceStr string for _, arg := range args { switch arg { case "-a": all = true case "-l": noRegex = true default: if !foundSearch { foundSearch = true search = arg } else if !foundReplace { foundReplace = true replaceStr = arg } else { InfoBar.Error("Invalid flag: " + arg) return } } } if noRegex { search = regexp.QuoteMeta(search) } replace := []byte(replaceStr) var regex *regexp.Regexp var err error if h.Buf.Settings["ignorecase"].(bool) { regex, err = regexp.Compile("(?im)" + search) } else { regex, err = regexp.Compile("(?m)" + search) } if err != nil { // There was an error with the user's regex InfoBar.Error(err) return } nreplaced := 0 start := h.Buf.Start() end := h.Buf.End() searchLoc := h.Cursor.Loc selection := h.Cursor.HasSelection() if selection { start = h.Cursor.CurSelection[0] end = h.Cursor.CurSelection[1] searchLoc = start // otherwise me might start at the end } if all { nreplaced, _ = h.Buf.ReplaceRegex(start, end, regex, replace, !noRegex) } else { inRange := func(l buffer.Loc) bool { return l.GreaterEqual(start) && l.LessEqual(end) } lastMatchEnd := buffer.Loc{-1, -1} var doReplacement func() doReplacement = func() { locs, found, err := h.Buf.FindNext(search, start, end, searchLoc, true, true) if err != nil { InfoBar.Error(err) return } if !found || !inRange(locs[0]) || !inRange(locs[1]) { h.Cursor.ResetSelection() h.Buf.RelocateCursors() return } if lastMatchEnd == locs[1] { // skip empty match right after previous match if searchLoc == end { searchLoc = start lastMatchEnd = buffer.Loc{-1, -1} } else { searchLoc = searchLoc.Move(1, h.Buf) } doReplacement() return } h.Cursor.SetSelectionStart(locs[0]) h.Cursor.SetSelectionEnd(locs[1]) h.GotoLoc(locs[0]) h.Buf.LastSearch = search h.Buf.LastSearchRegex = true h.Buf.HighlightSearch = h.Buf.Settings["hlsearch"].(bool) InfoBar.YNPrompt("Perform replacement (y,n,esc)", func(yes, canceled bool) { if !canceled && yes { _, nrunes := h.Buf.ReplaceRegex(locs[0], locs[1], regex, replace, !noRegex) searchLoc = locs[0] searchLoc.X += nrunes + locs[0].Diff(locs[1], h.Buf) if end.Y == locs[1].Y { end = end.Move(nrunes, h.Buf) } h.Cursor.Loc = searchLoc nreplaced++ } else if !canceled && !yes { searchLoc = locs[1] } else if canceled { h.Cursor.ResetSelection() h.Buf.RelocateCursors() return } lastMatchEnd = searchLoc doReplacement() }) } doReplacement() } h.Buf.RelocateCursors() h.Relocate() var s string if nreplaced > 1 { s = fmt.Sprintf("Replaced %d occurrences of %s", nreplaced, search) } else if nreplaced == 1 { s = fmt.Sprintf("Replaced 1 occurrence of %s", search) } else { s = fmt.Sprintf("Nothing matched %s", search) } if selection { s += " in selection" } InfoBar.Message(s) } // ReplaceAllCmd replaces search term all at once func (h *BufPane) ReplaceAllCmd(args []string) { // aliased to Replace command h.ReplaceCmd(append(args, "-a")) } func (h *BufPane) openTerm(args []string, newtab bool) { t := new(shell.Terminal) err := t.Start(args, false, true, nil, nil) if err != nil { InfoBar.Error(err) return } pane := 0 id := h.ID() if newtab { h.AddTab() id = MainTab().Panes[pane].ID() } else { for i, p := range MainTab().Panes { if p.IsActive() { pane = i id = p.ID() p.Close() break } } } v := h.GetView() tp, err := NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab()) if err != nil { InfoBar.Error(err) return } MainTab().Panes[pane] = tp MainTab().SetActive(pane) } // TermCmd opens a terminal in the current view func (h *BufPane) TermCmd(args []string) { if !TermEmuSupported { InfoBar.Error("Terminal emulator not supported on this system") return } if len(args) == 0 { sh := os.Getenv("SHELL") if sh == "" { InfoBar.Error("Shell environment not found") return } args = []string{sh} } // If there is only one open file we make a new tab instead of overwriting it newtab := len(MainTab().Panes) == 1 && len(Tabs.List) == 1 if newtab { h.openTerm(args, true) return } if h.Buf.Modified() && !h.Buf.Shared() { h.closePrompt("Save", func() { h.openTerm(args, false) }) } else { h.openTerm(args, false) } } // HandleCommand handles input from the user func (h *BufPane) HandleCommand(input string) { args, err := shellquote.Split(input) if err != nil { InfoBar.Error("Error parsing args ", err) return } if len(args) == 0 { return } inputCmd := args[0] if _, ok := commands[inputCmd]; !ok { InfoBar.Error("Unknown command ", inputCmd) } else { WriteLog("> " + input + "\n") commands[inputCmd].action(h, args[1:]) WriteLog("\n") } } zyedidia-micro-6a62575/internal/action/bufpane.go0000664000175000017510000006762115125206537021317 0ustar nileshnileshpackage action import ( "strings" "time" luar "layeh.com/gopher-luar" "github.com/micro-editor/tcell/v2" lua "github.com/yuin/gopher-lua" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/display" ulua "github.com/zyedidia/micro/v2/internal/lua" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) type BufAction any // BufKeyAction represents an action bound to a key. type BufKeyAction func(*BufPane) bool // BufMouseAction is an action that must be bound to a mouse event. type BufMouseAction func(*BufPane, *tcell.EventMouse) bool // BufBindings stores the bindings for the buffer pane type. var BufBindings *KeyTree // BufKeyActionGeneral makes a general pane action from a BufKeyAction. func BufKeyActionGeneral(a BufKeyAction) PaneKeyAction { return func(p Pane) bool { return a(p.(*BufPane)) } } // BufMouseActionGeneral makes a general pane mouse action from a BufKeyAction. func BufMouseActionGeneral(a BufMouseAction) PaneMouseAction { return func(p Pane, me *tcell.EventMouse) bool { return a(p.(*BufPane), me) } } func init() { BufBindings = NewKeyTree() } // LuaAction makes an action from a lua function. It returns either a BufKeyAction // or a BufMouseAction depending on the event type. func LuaAction(fn string, k Event) BufAction { luaFn := strings.Split(fn, ".") if len(luaFn) <= 1 { return nil } plName, plFn := luaFn[0], luaFn[1] pl := config.FindPlugin(plName) if pl == nil { return nil } var action BufAction switch k.(type) { case KeyEvent, KeySequenceEvent, RawEvent: action = BufKeyAction(func(h *BufPane) bool { val, err := pl.Call(plFn, luar.New(ulua.L, h)) if err != nil { screen.TermMessage(err) } if v, ok := val.(lua.LBool); !ok { return false } else { return bool(v) } }) case MouseEvent: action = BufMouseAction(func(h *BufPane, te *tcell.EventMouse) bool { val, err := pl.Call(plFn, luar.New(ulua.L, h), luar.New(ulua.L, te)) if err != nil { screen.TermMessage(err) } if v, ok := val.(lua.LBool); !ok { return false } else { return bool(v) } }) } return action } // BufMapEvent maps an event to an action func BufMapEvent(k Event, action string) { config.Bindings["buffer"][k.Name()] = action var actionfns []BufAction var names []string var types []byte for i := 0; ; i++ { if action == "" { break } idx := util.IndexAnyUnquoted(action, "&|,") a := action if idx >= 0 { a = action[:idx] types = append(types, action[idx]) action = action[idx+1:] } else { types = append(types, ' ') action = "" } var afn BufAction if strings.HasPrefix(a, "command:") { a = strings.SplitN(a, ":", 2)[1] afn = CommandAction(a) names = append(names, "") } else if strings.HasPrefix(a, "command-edit:") { a = strings.SplitN(a, ":", 2)[1] afn = CommandEditAction(a) names = append(names, "") } else if strings.HasPrefix(a, "lua:") { a = strings.SplitN(a, ":", 2)[1] afn = LuaAction(a, k) if afn == nil { screen.TermMessage("Lua Error:", a, "does not exist") continue } split := strings.SplitN(a, ".", 2) if len(split) > 1 { a = strings.Title(split[0]) + strings.Title(split[1]) } else { a = strings.Title(a) } names = append(names, a) } else if f, ok := BufKeyActions[a]; ok { afn = f names = append(names, a) } else if f, ok := BufMouseActions[a]; ok { afn = f names = append(names, a) } else { screen.TermMessage("Error in bindings: action", a, "does not exist") continue } actionfns = append(actionfns, afn) } bufAction := func(h *BufPane, te *tcell.EventMouse) bool { for i, a := range actionfns { var success bool if _, ok := MultiActions[names[i]]; ok { success = true for _, c := range h.Buf.GetCursors() { h.Buf.SetCurCursor(c.Num) h.Cursor = c success = success && h.execAction(a, names[i], te) } } else { h.Buf.SetCurCursor(0) h.Cursor = h.Buf.GetActiveCursor() success = h.execAction(a, names[i], te) } // if the action changed the current pane, update the reference h = MainTab().CurPane() if h == nil { // stop, in case the current pane is not a BufPane break } if (!success && types[i] == '&') || (success && types[i] == '|') { break } } return true } switch e := k.(type) { case KeyEvent, KeySequenceEvent, RawEvent: BufBindings.RegisterKeyBinding(e, BufKeyActionGeneral(func(h *BufPane) bool { return bufAction(h, nil) })) case MouseEvent: BufBindings.RegisterMouseBinding(e, BufMouseActionGeneral(bufAction)) } } // BufUnmap unmaps a key or mouse event from any action func BufUnmap(k Event) { // TODO // delete(BufKeyBindings, k) // // switch e := k.(type) { // case MouseEvent: // delete(BufMouseBindings, e) // } } // The BufPane connects the buffer and the window // It provides a cursor (or multiple) and defines a set of actions // that can be taken on the buffer // The ActionHandler can access the window for necessary info about // visual positions for mouse clicks and scrolling type BufPane struct { display.BWindow // Buf is the buffer this BufPane views Buf *buffer.Buffer // Bindings stores the association of key events and actions bindings *KeyTree // Cursor is the currently active buffer cursor Cursor *buffer.Cursor // Since tcell doesn't differentiate between a mouse press event // and a mouse move event with button pressed (nor between a mouse // release event and a mouse move event with no buttons pressed), // we need to keep track of whether or not the mouse was previously // pressed, to determine mouse release and mouse drag events. // Moreover, since in case of a release event tcell doesn't tell us // which button was released, we need to keep track of which // (possibly multiple) buttons were pressed previously. mousePressed map[MouseEvent]bool // This stores when the last click was // This is useful for detecting double and triple clicks lastClickTime time.Time lastLoc buffer.Loc // freshClip returns true if one or more lines have been cut to the clipboard // and have never been pasted yet. freshClip bool // Was the last mouse event actually a double click? // Useful for detecting triple clicks -- if a double click is detected // but the last mouse event was actually a double click, it's a triple click DoubleClick bool // Same here, just to keep track for mouse move events TripleClick bool // Should the current multiple cursor selection search based on word or // based on selection (false for selection, true for word) multiWord bool splitID uint64 tab *Tab // remember original location of a search in case the search is canceled searchOrig buffer.Loc // The pane may not yet be fully initialized after its creation // since we may not know the window geometry yet. In such case we finish // its initialization a bit later, after the initial resize. initialized bool } func newBufPane(buf *buffer.Buffer, win display.BWindow, tab *Tab) *BufPane { h := new(BufPane) h.Buf = buf h.BWindow = win h.tab = tab h.Cursor = h.Buf.GetActiveCursor() h.mousePressed = make(map[MouseEvent]bool) return h } // NewBufPane creates a new buffer pane with the given window. func NewBufPane(buf *buffer.Buffer, win display.BWindow, tab *Tab) *BufPane { h := newBufPane(buf, win, tab) h.finishInitialize() return h } // NewBufPaneFromBuf constructs a new pane from the given buffer and automatically // creates a buf window. func NewBufPaneFromBuf(buf *buffer.Buffer, tab *Tab) *BufPane { w := display.NewBufWindow(0, 0, 0, 0, buf) h := newBufPane(buf, w, tab) // Postpone finishing initializing the pane until we know the actual geometry // of the buf window. return h } // TODO: make sure splitID and tab are set before finishInitialize is called func (h *BufPane) finishInitialize() { h.initialRelocate() h.initialized = true err := config.RunPluginFn("onBufPaneOpen", luar.New(ulua.L, h)) if err != nil { screen.TermMessage(err) } } // Resize resizes the pane func (h *BufPane) Resize(width, height int) { h.BWindow.Resize(width, height) if !h.initialized { h.finishInitialize() } } // SetTab sets this pane's tab. func (h *BufPane) SetTab(t *Tab) { h.tab = t } // Tab returns this pane's tab. func (h *BufPane) Tab() *Tab { return h.tab } func (h *BufPane) ResizePane(size int) { n := h.tab.GetNode(h.splitID) n.ResizeSplit(size) h.tab.Resize() } // PluginCB calls all plugin callbacks with a certain name and displays an // error if there is one and returns the aggregate boolean response. // The bufpane is passed as the first argument to the callbacks, // optional args are passed as the next arguments. func (h *BufPane) PluginCB(cb string, args ...any) bool { largs := []lua.LValue{luar.New(ulua.L, h)} for _, a := range args { largs = append(largs, luar.New(ulua.L, a)) } b, err := config.RunPluginFnBool(h.Buf.Settings, cb, largs...) if err != nil { screen.TermMessage(err) } return b } func (h *BufPane) resetMouse() { for me := range h.mousePressed { delete(h.mousePressed, me) } } // OpenBuffer opens the given buffer in this pane. func (h *BufPane) OpenBuffer(b *buffer.Buffer) { h.Buf.Close() h.Buf = b h.BWindow.SetBuffer(b) h.Cursor = b.GetActiveCursor() h.Resize(h.GetView().Width, h.GetView().Height) h.initialRelocate() // Set mouseReleased to true because we assume the mouse is not being // pressed when the editor is opened h.resetMouse() h.lastClickTime = time.Time{} } // GotoLoc moves the cursor to a new location and adjusts the view accordingly. // Use GotoLoc when the new location may be far away from the current location. func (h *BufPane) GotoLoc(loc buffer.Loc) { sloc := h.SLocFromLoc(loc) d := h.Diff(h.SLocFromLoc(h.Cursor.Loc), sloc) h.Cursor.GotoLoc(loc) // If the new location is far away from the previous one, // ensure the cursor is at 25% of the window height height := h.BufView().Height if util.Abs(d) >= height { v := h.GetView() v.StartLine = h.Scroll(sloc, -height/4) h.ScrollAdjust() v.StartCol = 0 } h.Relocate() } func (h *BufPane) initialRelocate() { sloc := h.SLocFromLoc(h.Cursor.Loc) height := h.BufView().Height // If the initial cursor location is far away from the beginning // of the buffer, ensure the cursor is at 25% of the window height v := h.GetView() if h.Diff(display.SLoc{0, 0}, sloc) < height { v.StartLine = display.SLoc{0, 0} } else { v.StartLine = h.Scroll(sloc, -height/4) h.ScrollAdjust() } v.StartCol = 0 h.Relocate() } // ID returns this pane's split id. func (h *BufPane) ID() uint64 { return h.splitID } // SetID sets the split ID of this pane. func (h *BufPane) SetID(i uint64) { h.splitID = i } // Name returns the BufPane's name. func (h *BufPane) Name() string { n := h.Buf.GetName() if h.Buf.Modified() { n += " +" } return n } // ReOpen reloads the file opened in the bufpane from disk func (h *BufPane) ReOpen() { h.Buf.ReOpen() h.Relocate() } func (h *BufPane) getReloadSetting() string { reloadSetting := h.Buf.Settings["reload"] return reloadSetting.(string) } // HandleEvent executes the tcell event properly func (h *BufPane) HandleEvent(event tcell.Event) { if h.Buf.ExternallyModified() && !h.Buf.ReloadDisabled { reload := h.getReloadSetting() if reload == "prompt" { InfoBar.YNPrompt("The file on disk has changed. Reload file? (y,n,esc)", func(yes, canceled bool) { if canceled { h.Buf.DisableReload() } if !yes || canceled { h.Buf.UpdateModTime() } else { h.ReOpen() } }) } else if reload == "auto" { h.ReOpen() } else if reload == "disabled" { h.Buf.DisableReload() } else { InfoBar.Message("Invalid reload setting") } } switch e := event.(type) { case *tcell.EventRaw: re := RawEvent{ esc: e.EscSeq(), } h.DoKeyEvent(re) case *tcell.EventPaste: h.paste(e.Text()) h.Relocate() case *tcell.EventKey: ke := keyEvent(e) done := h.DoKeyEvent(ke) if !done && e.Key() == tcell.KeyRune { h.DoRuneInsert(e.Rune()) } case *tcell.EventMouse: if e.Buttons() != tcell.ButtonNone { me := MouseEvent{ btn: e.Buttons(), mod: metaToAlt(e.Modifiers()), state: MousePress, } isDrag := len(h.mousePressed) > 0 if e.Buttons() & ^(tcell.WheelUp|tcell.WheelDown|tcell.WheelLeft|tcell.WheelRight) != tcell.ButtonNone { h.mousePressed[me] = true } if isDrag { me.state = MouseDrag } h.DoMouseEvent(me, e) } else { // Mouse event with no click - mouse was just released. // If there were multiple mouse buttons pressed, we don't know which one // was actually released, so we assume they all were released. pressed := len(h.mousePressed) > 0 for me := range h.mousePressed { delete(h.mousePressed, me) me.state = MouseRelease h.DoMouseEvent(me, e) } if !pressed { // Propagate the mouse release in case the press wasn't for this BufPane Tabs.ResetMouse() } } } h.Buf.MergeCursors() if h.IsActive() { // Display any gutter messages for this line c := h.Buf.GetActiveCursor() none := true for _, m := range h.Buf.Messages { if c.Y == m.Start.Y || c.Y == m.End.Y { InfoBar.GutterMessage(m.Msg) none = false break } } if none && InfoBar.HasGutter { InfoBar.ClearGutter() } } cursors := h.Buf.GetCursors() for _, c := range cursors { if c.NewTrailingWsY != c.Y && (!c.HasSelection() || (c.NewTrailingWsY != c.CurSelection[0].Y && c.NewTrailingWsY != c.CurSelection[1].Y)) { c.NewTrailingWsY = -1 } } } // Bindings returns the current bindings tree for this buffer. func (h *BufPane) Bindings() *KeyTree { if h.bindings != nil { return h.bindings } return BufBindings } // DoKeyEvent executes a key event by finding the action it is bound // to and executing it (possibly multiple times for multiple cursors). // Returns true if the action was executed OR if there are more keys // remaining to process before executing an action (if this is a key // sequence event). Returns false if no action found. func (h *BufPane) DoKeyEvent(e Event) bool { binds := h.Bindings() action, more := binds.NextEvent(e, nil) if action != nil && !more { action(h) binds.ResetEvents() return true } else if action == nil && !more { binds.ResetEvents() } return more } func (h *BufPane) execAction(action BufAction, name string, te *tcell.EventMouse) bool { if name != "Autocomplete" && name != "CycleAutocompleteBack" { h.Buf.HasSuggestions = false } if !h.PluginCB("pre"+name, te) { return false } var success bool switch a := action.(type) { case BufKeyAction: success = a(h) case BufMouseAction: success = a(h, te) } success = success && h.PluginCB("on"+name, te) if _, ok := MultiActions[name]; ok { if recordingMacro { if name != "ToggleMacro" && name != "PlayMacro" { curmacro = append(curmacro, action) } } } return success } func (h *BufPane) completeAction(action string) { h.PluginCB("on" + action) } func (h *BufPane) HasKeyEvent(e Event) bool { // TODO return true // _, ok := BufKeyBindings[e] // return ok } // DoMouseEvent executes a mouse event by finding the action it is bound // to and executing it func (h *BufPane) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool { binds := h.Bindings() action, _ := binds.NextEvent(e, te) if action != nil { action(h) binds.ResetEvents() return true } // TODO return false // if action, ok := BufMouseBindings[e]; ok { // if action(h, te) { // h.Relocate() // } // return true // } else if h.HasKeyEvent(e) { // return h.DoKeyEvent(e) // } // return false } // DoRuneInsert inserts a given rune into the current buffer // (possibly multiple times for multiple cursors) func (h *BufPane) DoRuneInsert(r rune) { cursors := h.Buf.GetCursors() for _, c := range cursors { // Insert a character h.Buf.SetCurCursor(c.Num) h.Cursor = c if !h.PluginCB("preRune", string(r)) { continue } if c.HasSelection() { c.DeleteSelection() c.ResetSelection() } if h.Buf.OverwriteMode { next := c.Loc next.X++ h.Buf.Replace(c.Loc, next, string(r)) } else { h.Buf.Insert(c.Loc, string(r)) } if recordingMacro { curmacro = append(curmacro, r) } h.Relocate() h.PluginCB("onRune", string(r)) } } // VSplitIndex opens the given buffer in a vertical split on the given side. func (h *BufPane) VSplitIndex(buf *buffer.Buffer, right bool) *BufPane { e := NewBufPaneFromBuf(buf, h.tab) e.splitID = h.tab.GetNode(h.splitID).VSplit(right) currentPaneIdx := h.tab.GetPane(h.splitID) if right { currentPaneIdx++ } h.tab.AddPane(e, currentPaneIdx) h.tab.Resize() h.tab.SetActive(currentPaneIdx) return e } // HSplitIndex opens the given buffer in a horizontal split on the given side. func (h *BufPane) HSplitIndex(buf *buffer.Buffer, bottom bool) *BufPane { e := NewBufPaneFromBuf(buf, h.tab) e.splitID = h.tab.GetNode(h.splitID).HSplit(bottom) currentPaneIdx := h.tab.GetPane(h.splitID) if bottom { currentPaneIdx++ } h.tab.AddPane(e, currentPaneIdx) h.tab.Resize() h.tab.SetActive(currentPaneIdx) return e } // VSplitBuf opens the given buffer in a new vertical split. func (h *BufPane) VSplitBuf(buf *buffer.Buffer) *BufPane { return h.VSplitIndex(buf, h.Buf.Settings["splitright"].(bool)) } // HSplitBuf opens the given buffer in a new horizontal split. func (h *BufPane) HSplitBuf(buf *buffer.Buffer) *BufPane { return h.HSplitIndex(buf, h.Buf.Settings["splitbottom"].(bool)) } // Close this pane. func (h *BufPane) Close() { h.Buf.Close() } // SetActive marks this pane as active. func (h *BufPane) SetActive(b bool) { if h.IsActive() == b { return } h.BWindow.SetActive(b) if b { // Display any gutter messages for this line c := h.Buf.GetActiveCursor() none := true for _, m := range h.Buf.Messages { if c.Y == m.Start.Y || c.Y == m.End.Y { InfoBar.GutterMessage(m.Msg) none = false break } } if none && InfoBar.HasGutter { InfoBar.ClearGutter() } err := config.RunPluginFn("onSetActive", luar.New(ulua.L, h)) if err != nil { screen.TermMessage(err) } } } // BufKeyActions contains the list of all possible key actions the bufhandler could execute var BufKeyActions = map[string]BufKeyAction{ "CursorUp": (*BufPane).CursorUp, "CursorDown": (*BufPane).CursorDown, "CursorPageUp": (*BufPane).CursorPageUp, "CursorPageDown": (*BufPane).CursorPageDown, "CursorLeft": (*BufPane).CursorLeft, "CursorRight": (*BufPane).CursorRight, "CursorStart": (*BufPane).CursorStart, "CursorEnd": (*BufPane).CursorEnd, "CursorToViewTop": (*BufPane).CursorToViewTop, "CursorToViewCenter": (*BufPane).CursorToViewCenter, "CursorToViewBottom": (*BufPane).CursorToViewBottom, "SelectToStart": (*BufPane).SelectToStart, "SelectToEnd": (*BufPane).SelectToEnd, "SelectUp": (*BufPane).SelectUp, "SelectDown": (*BufPane).SelectDown, "SelectLeft": (*BufPane).SelectLeft, "SelectRight": (*BufPane).SelectRight, "WordRight": (*BufPane).WordRight, "WordLeft": (*BufPane).WordLeft, "SubWordRight": (*BufPane).SubWordRight, "SubWordLeft": (*BufPane).SubWordLeft, "SelectWordRight": (*BufPane).SelectWordRight, "SelectWordLeft": (*BufPane).SelectWordLeft, "SelectSubWordRight": (*BufPane).SelectSubWordRight, "SelectSubWordLeft": (*BufPane).SelectSubWordLeft, "DeleteWordRight": (*BufPane).DeleteWordRight, "DeleteWordLeft": (*BufPane).DeleteWordLeft, "DeleteSubWordRight": (*BufPane).DeleteSubWordRight, "DeleteSubWordLeft": (*BufPane).DeleteSubWordLeft, "SelectLine": (*BufPane).SelectLine, "SelectToStartOfLine": (*BufPane).SelectToStartOfLine, "SelectToStartOfText": (*BufPane).SelectToStartOfText, "SelectToStartOfTextToggle": (*BufPane).SelectToStartOfTextToggle, "SelectToEndOfLine": (*BufPane).SelectToEndOfLine, "ParagraphPrevious": (*BufPane).ParagraphPrevious, "ParagraphNext": (*BufPane).ParagraphNext, "SelectToParagraphPrevious": (*BufPane).SelectToParagraphPrevious, "SelectToParagraphNext": (*BufPane).SelectToParagraphNext, "InsertNewline": (*BufPane).InsertNewline, "Backspace": (*BufPane).Backspace, "Delete": (*BufPane).Delete, "InsertTab": (*BufPane).InsertTab, "Save": (*BufPane).Save, "SaveAll": (*BufPane).SaveAll, "SaveAs": (*BufPane).SaveAs, "Find": (*BufPane).Find, "FindLiteral": (*BufPane).FindLiteral, "FindNext": (*BufPane).FindNext, "FindPrevious": (*BufPane).FindPrevious, "DiffNext": (*BufPane).DiffNext, "DiffPrevious": (*BufPane).DiffPrevious, "Center": (*BufPane).Center, "Undo": (*BufPane).Undo, "Redo": (*BufPane).Redo, "Copy": (*BufPane).Copy, "CopyLine": (*BufPane).CopyLine, "Cut": (*BufPane).Cut, "CutLine": (*BufPane).CutLine, "Duplicate": (*BufPane).Duplicate, "DuplicateLine": (*BufPane).DuplicateLine, "DeleteLine": (*BufPane).DeleteLine, "MoveLinesUp": (*BufPane).MoveLinesUp, "MoveLinesDown": (*BufPane).MoveLinesDown, "IndentSelection": (*BufPane).IndentSelection, "OutdentSelection": (*BufPane).OutdentSelection, "Autocomplete": (*BufPane).Autocomplete, "CycleAutocompleteBack": (*BufPane).CycleAutocompleteBack, "OutdentLine": (*BufPane).OutdentLine, "IndentLine": (*BufPane).IndentLine, "Paste": (*BufPane).Paste, "PastePrimary": (*BufPane).PastePrimary, "SelectAll": (*BufPane).SelectAll, "OpenFile": (*BufPane).OpenFile, "Start": (*BufPane).Start, "End": (*BufPane).End, "PageUp": (*BufPane).PageUp, "PageDown": (*BufPane).PageDown, "SelectPageUp": (*BufPane).SelectPageUp, "SelectPageDown": (*BufPane).SelectPageDown, "HalfPageUp": (*BufPane).HalfPageUp, "HalfPageDown": (*BufPane).HalfPageDown, "StartOfText": (*BufPane).StartOfText, "StartOfTextToggle": (*BufPane).StartOfTextToggle, "StartOfLine": (*BufPane).StartOfLine, "EndOfLine": (*BufPane).EndOfLine, "ToggleHelp": (*BufPane).ToggleHelp, "ToggleKeyMenu": (*BufPane).ToggleKeyMenu, "ToggleDiffGutter": (*BufPane).ToggleDiffGutter, "ToggleRuler": (*BufPane).ToggleRuler, "ToggleHighlightSearch": (*BufPane).ToggleHighlightSearch, "UnhighlightSearch": (*BufPane).UnhighlightSearch, "ResetSearch": (*BufPane).ResetSearch, "ClearStatus": (*BufPane).ClearStatus, "ShellMode": (*BufPane).ShellMode, "CommandMode": (*BufPane).CommandMode, "ToggleOverwriteMode": (*BufPane).ToggleOverwriteMode, "Escape": (*BufPane).Escape, "Quit": (*BufPane).Quit, "QuitAll": (*BufPane).QuitAll, "ForceQuit": (*BufPane).ForceQuit, "AddTab": (*BufPane).AddTab, "PreviousTab": (*BufPane).PreviousTab, "NextTab": (*BufPane).NextTab, "FirstTab": (*BufPane).FirstTab, "LastTab": (*BufPane).LastTab, "NextSplit": (*BufPane).NextSplit, "PreviousSplit": (*BufPane).PreviousSplit, "FirstSplit": (*BufPane).FirstSplit, "LastSplit": (*BufPane).LastSplit, "Unsplit": (*BufPane).Unsplit, "VSplit": (*BufPane).VSplitAction, "HSplit": (*BufPane).HSplitAction, "ToggleMacro": (*BufPane).ToggleMacro, "PlayMacro": (*BufPane).PlayMacro, "Suspend": (*BufPane).Suspend, "ScrollUp": (*BufPane).ScrollUpAction, "ScrollDown": (*BufPane).ScrollDownAction, "SpawnMultiCursor": (*BufPane).SpawnMultiCursor, "SpawnMultiCursorUp": (*BufPane).SpawnMultiCursorUp, "SpawnMultiCursorDown": (*BufPane).SpawnMultiCursorDown, "SpawnMultiCursorSelect": (*BufPane).SpawnMultiCursorSelect, "RemoveMultiCursor": (*BufPane).RemoveMultiCursor, "RemoveAllMultiCursors": (*BufPane).RemoveAllMultiCursors, "SkipMultiCursor": (*BufPane).SkipMultiCursor, "SkipMultiCursorBack": (*BufPane).SkipMultiCursorBack, "JumpToMatchingBrace": (*BufPane).JumpToMatchingBrace, "JumpLine": (*BufPane).JumpLine, "Deselect": (*BufPane).Deselect, "ClearInfo": (*BufPane).ClearInfo, "None": (*BufPane).None, // This was changed to InsertNewline but I don't want to break backwards compatibility "InsertEnter": (*BufPane).InsertNewline, } // BufMouseActions contains the list of all possible mouse actions the bufhandler could execute var BufMouseActions = map[string]BufMouseAction{ "MousePress": (*BufPane).MousePress, "MouseDrag": (*BufPane).MouseDrag, "MouseRelease": (*BufPane).MouseRelease, "MouseMultiCursor": (*BufPane).MouseMultiCursor, } // MultiActions is a list of actions that should be executed multiple // times if there are multiple cursors (one per cursor) // Generally actions that modify global editor state like quitting or // saving should not be included in this list var MultiActions = map[string]bool{ "CursorUp": true, "CursorDown": true, "CursorPageUp": true, "CursorPageDown": true, "CursorLeft": true, "CursorRight": true, "CursorStart": true, "CursorEnd": true, "SelectToStart": true, "SelectToEnd": true, "SelectUp": true, "SelectDown": true, "SelectLeft": true, "SelectRight": true, "WordRight": true, "WordLeft": true, "SubWordRight": true, "SubWordLeft": true, "SelectWordRight": true, "SelectWordLeft": true, "SelectSubWordRight": true, "SelectSubWordLeft": true, "DeleteWordRight": true, "DeleteWordLeft": true, "DeleteSubWordRight": true, "DeleteSubWordLeft": true, "SelectLine": true, "SelectToStartOfLine": true, "SelectToStartOfText": true, "SelectToStartOfTextToggle": true, "SelectToEndOfLine": true, "ParagraphPrevious": true, "ParagraphNext": true, "InsertNewline": true, "Backspace": true, "Delete": true, "InsertTab": true, "FindNext": true, "FindPrevious": true, "CopyLine": true, "Copy": true, "Cut": true, "CutLine": true, "Duplicate": true, "DuplicateLine": true, "DeleteLine": true, "MoveLinesUp": true, "MoveLinesDown": true, "IndentSelection": true, "OutdentSelection": true, "OutdentLine": true, "IndentLine": true, "Paste": true, "PastePrimary": true, "SelectPageUp": true, "SelectPageDown": true, "StartOfLine": true, "StartOfText": true, "StartOfTextToggle": true, "EndOfLine": true, "JumpToMatchingBrace": true, } zyedidia-micro-6a62575/internal/action/bindings.go0000664000175000017510000003206215125206537021463 0ustar nileshnileshpackage action import ( "encoding/json" "errors" "fmt" "io/fs" "os" "path/filepath" "regexp" "strings" "unicode" "github.com/micro-editor/json5" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) var Binder = map[string]func(e Event, action string){ "command": InfoMapEvent, "buffer": BufMapEvent, "terminal": TermMapEvent, } func writeFile(name string, txt []byte) error { return util.SafeWrite(name, txt, false) } func createBindingsIfNotExist(fname string) { if _, e := os.Stat(fname); errors.Is(e, fs.ErrNotExist) { writeFile(fname, []byte("{}")) } } // InitBindings intializes the bindings map by reading from bindings.json func InitBindings() { var parsed map[string]any filename := filepath.Join(config.ConfigDir, "bindings.json") createBindingsIfNotExist(filename) if _, e := os.Stat(filename); e == nil { input, err := os.ReadFile(filename) if err != nil { screen.TermMessage("Error reading bindings.json file: " + err.Error()) return } err = json5.Unmarshal(input, &parsed) if err != nil { screen.TermMessage("Error reading bindings.json:", err.Error()) } } for p, bind := range Binder { defaults := DefaultBindings(p) for k, v := range defaults { BindKey(k, v, bind) } } for k, v := range parsed { switch val := v.(type) { case string: BindKey(k, val, Binder["buffer"]) case map[string]any: bind, ok := Binder[k] if !ok || bind == nil { screen.TermMessage(fmt.Sprintf("%s is not a valid pane type", k)) continue } for e, a := range val { s, ok := a.(string) if !ok { screen.TermMessage("Error reading bindings.json: non-string and non-map entry", k) } else { BindKey(e, s, bind) } } default: screen.TermMessage("Error reading bindings.json: non-string and non-map entry", k) } } } func BindKey(k, v string, bind func(e Event, a string)) { event, err := findEvent(k) if err != nil { screen.TermMessage(err) return } if strings.HasPrefix(k, "\x1b") { screen.RegisterRawSeq(k) } bind(event, v) // switch e := event.(type) { // case KeyEvent: // InfoMapKey(e, v) // case KeySequenceEvent: // InfoMapKey(e, v) // case MouseEvent: // InfoMapMouse(e, v) // case RawEvent: // InfoMapKey(e, v) // } } var r = regexp.MustCompile("<(.+?)>") func findEvents(k string) (b KeySequenceEvent, ok bool, err error) { var events []Event = nil for len(k) > 0 { groups := r.FindStringSubmatchIndex(k) if len(groups) > 3 { if events == nil { events = make([]Event, 0, 3) } e, ok := findSingleEvent(k[groups[2]:groups[3]]) if !ok { return KeySequenceEvent{}, false, errors.New("Invalid event " + k[groups[2]:groups[3]]) } events = append(events, e) k = k[groups[3]+1:] } else { return KeySequenceEvent{}, false, nil } } return KeySequenceEvent{events}, true, nil } // findSingleEvent will find binding Key 'b' using string 'k' func findSingleEvent(k string) (b Event, ok bool) { modifiers := tcell.ModNone // First, we'll strip off all the modifiers in the name and add them to the // ModMask modSearch: for { switch { case strings.HasPrefix(k, "-") && k != "-": // We optionally support dashes between modifiers k = k[1:] case strings.HasPrefix(k, "Ctrl") && k != "CtrlH": // CtrlH technically does not have a 'Ctrl' modifier because it is really backspace k = k[4:] modifiers |= tcell.ModCtrl case strings.HasPrefix(k, "Alt"): k = k[3:] modifiers |= tcell.ModAlt case strings.HasPrefix(k, "Shift"): k = k[5:] modifiers |= tcell.ModShift case strings.HasPrefix(k, "\x1b"): return RawEvent{ esc: k, }, true default: break modSearch } } if k == "" { return KeyEvent{}, false } // Control is handled in a special way, since the terminal sends explicitly // marked escape sequences for control keys // We should check for Control keys first if modifiers&tcell.ModCtrl != 0 { // see if the key is in bindingKeys with the Ctrl prefix. k = string(unicode.ToUpper(rune(k[0]))) + k[1:] if code, ok := keyEvents["Ctrl"+k]; ok { return KeyEvent{ code: code, mod: modifiers, }, true } } // See if we can find the key in bindingKeys if code, ok := keyEvents[k]; ok { return KeyEvent{ code: code, mod: modifiers, }, true } var mstate MouseState = MousePress if strings.HasSuffix(k, "Drag") { k = k[:len(k)-4] mstate = MouseDrag } else if strings.HasSuffix(k, "Release") { k = k[:len(k)-7] mstate = MouseRelease } // See if we can find the key in bindingMouse if code, ok := mouseEvents[k]; ok { return MouseEvent{ btn: code, mod: modifiers, state: mstate, }, true } // If we were given one character, then we've got a rune. if len(k) == 1 { return KeyEvent{ code: tcell.KeyRune, mod: modifiers, r: rune(k[0]), }, true } // We don't know what happened. return KeyEvent{}, false } func findEvent(k string) (Event, error) { var event Event event, ok, err := findEvents(k) if err != nil { return nil, err } if !ok { event, ok = findSingleEvent(k) if !ok { return nil, errors.New(k + " is not a bindable event") } } return event, nil } func eventsEqual(e1 Event, e2 Event) bool { seq1, ok1 := e1.(KeySequenceEvent) seq2, ok2 := e2.(KeySequenceEvent) if ok1 && ok2 { if len(seq1.keys) != len(seq2.keys) { return false } for i := 0; i < len(seq1.keys); i++ { if seq1.keys[i] != seq2.keys[i] { return false } } return true } return e1 == e2 } // TryBindKeyPlug tries to bind a key for the plugin without writing to bindings.json. // This operation can be rejected by lockbindings to prevent unexpected actions by the user. func TryBindKeyPlug(k, v string, overwrite bool) (bool, error) { if l, ok := config.GlobalSettings["lockbindings"]; ok && l.(bool) { return false, errors.New("bindings is locked by the user") } return TryBindKey(k, v, overwrite, false) } // TryBindKey tries to bind a key by writing to config.ConfigDir/bindings.json // Returns true if the keybinding already existed or is binded successfully and a possible error func TryBindKey(k, v string, overwrite bool, writeToFile bool) (bool, error) { var e error var parsed map[string]any filename := filepath.Join(config.ConfigDir, "bindings.json") createBindingsIfNotExist(filename) if _, e = os.Stat(filename); e == nil { input, err := os.ReadFile(filename) if err != nil { return false, errors.New("Error reading bindings.json file: " + err.Error()) } err = json5.Unmarshal(input, &parsed) if err != nil { return false, errors.New("Error reading bindings.json: " + err.Error()) } key, err := findEvent(k) if err != nil { return false, err } found := false var ev string for ev = range parsed { if e, err := findEvent(ev); err == nil { if eventsEqual(e, key) { found = true break } } } if found { if overwrite { parsed[ev] = v } else { return true, nil } } else { parsed[k] = v } BindKey(k, v, Binder["buffer"]) txt, _ := json.MarshalIndent(parsed, "", " ") txt = append(txt, '\n') if writeToFile { return true, writeFile(filename, txt) } else { return true, nil } } return false, e } // UnbindKey removes the binding for a key from the bindings.json file func UnbindKey(k string) error { var e error var parsed map[string]any filename := filepath.Join(config.ConfigDir, "bindings.json") createBindingsIfNotExist(filename) if _, e = os.Stat(filename); e == nil { input, err := os.ReadFile(filename) if err != nil { return errors.New("Error reading bindings.json file: " + err.Error()) } err = json5.Unmarshal(input, &parsed) if err != nil { return errors.New("Error reading bindings.json: " + err.Error()) } key, err := findEvent(k) if err != nil { return err } for ev := range parsed { if e, err := findEvent(ev); err == nil { if eventsEqual(e, key) { delete(parsed, ev) break } } } if strings.HasPrefix(k, "\x1b") { screen.UnregisterRawSeq(k) } defaults := DefaultBindings("buffer") if a, ok := defaults[k]; ok { BindKey(k, a, Binder["buffer"]) } else if _, ok := config.Bindings["buffer"][k]; ok { BufUnmap(key) delete(config.Bindings["buffer"], k) } txt, _ := json.MarshalIndent(parsed, "", " ") txt = append(txt, '\n') return writeFile(filename, txt) } return e } var mouseEvents = map[string]tcell.ButtonMask{ "MouseLeft": tcell.ButtonPrimary, "MouseMiddle": tcell.ButtonMiddle, "MouseRight": tcell.ButtonSecondary, "MouseWheelUp": tcell.WheelUp, "MouseWheelDown": tcell.WheelDown, "MouseWheelLeft": tcell.WheelLeft, "MouseWheelRight": tcell.WheelRight, } var keyEvents = map[string]tcell.Key{ "Up": tcell.KeyUp, "Down": tcell.KeyDown, "Right": tcell.KeyRight, "Left": tcell.KeyLeft, "UpLeft": tcell.KeyUpLeft, "UpRight": tcell.KeyUpRight, "DownLeft": tcell.KeyDownLeft, "DownRight": tcell.KeyDownRight, "Center": tcell.KeyCenter, "PageUp": tcell.KeyPgUp, "PageDown": tcell.KeyPgDn, "Home": tcell.KeyHome, "End": tcell.KeyEnd, "Insert": tcell.KeyInsert, "Delete": tcell.KeyDelete, "Help": tcell.KeyHelp, "Exit": tcell.KeyExit, "Clear": tcell.KeyClear, "Cancel": tcell.KeyCancel, "Print": tcell.KeyPrint, "Pause": tcell.KeyPause, "Backtab": tcell.KeyBacktab, "F1": tcell.KeyF1, "F2": tcell.KeyF2, "F3": tcell.KeyF3, "F4": tcell.KeyF4, "F5": tcell.KeyF5, "F6": tcell.KeyF6, "F7": tcell.KeyF7, "F8": tcell.KeyF8, "F9": tcell.KeyF9, "F10": tcell.KeyF10, "F11": tcell.KeyF11, "F12": tcell.KeyF12, "F13": tcell.KeyF13, "F14": tcell.KeyF14, "F15": tcell.KeyF15, "F16": tcell.KeyF16, "F17": tcell.KeyF17, "F18": tcell.KeyF18, "F19": tcell.KeyF19, "F20": tcell.KeyF20, "F21": tcell.KeyF21, "F22": tcell.KeyF22, "F23": tcell.KeyF23, "F24": tcell.KeyF24, "F25": tcell.KeyF25, "F26": tcell.KeyF26, "F27": tcell.KeyF27, "F28": tcell.KeyF28, "F29": tcell.KeyF29, "F30": tcell.KeyF30, "F31": tcell.KeyF31, "F32": tcell.KeyF32, "F33": tcell.KeyF33, "F34": tcell.KeyF34, "F35": tcell.KeyF35, "F36": tcell.KeyF36, "F37": tcell.KeyF37, "F38": tcell.KeyF38, "F39": tcell.KeyF39, "F40": tcell.KeyF40, "F41": tcell.KeyF41, "F42": tcell.KeyF42, "F43": tcell.KeyF43, "F44": tcell.KeyF44, "F45": tcell.KeyF45, "F46": tcell.KeyF46, "F47": tcell.KeyF47, "F48": tcell.KeyF48, "F49": tcell.KeyF49, "F50": tcell.KeyF50, "F51": tcell.KeyF51, "F52": tcell.KeyF52, "F53": tcell.KeyF53, "F54": tcell.KeyF54, "F55": tcell.KeyF55, "F56": tcell.KeyF56, "F57": tcell.KeyF57, "F58": tcell.KeyF58, "F59": tcell.KeyF59, "F60": tcell.KeyF60, "F61": tcell.KeyF61, "F62": tcell.KeyF62, "F63": tcell.KeyF63, "F64": tcell.KeyF64, "CtrlSpace": tcell.KeyCtrlSpace, "CtrlA": tcell.KeyCtrlA, "CtrlB": tcell.KeyCtrlB, "CtrlC": tcell.KeyCtrlC, "CtrlD": tcell.KeyCtrlD, "CtrlE": tcell.KeyCtrlE, "CtrlF": tcell.KeyCtrlF, "CtrlG": tcell.KeyCtrlG, "CtrlH": tcell.KeyCtrlH, "CtrlI": tcell.KeyCtrlI, "CtrlJ": tcell.KeyCtrlJ, "CtrlK": tcell.KeyCtrlK, "CtrlL": tcell.KeyCtrlL, "CtrlM": tcell.KeyCtrlM, "CtrlN": tcell.KeyCtrlN, "CtrlO": tcell.KeyCtrlO, "CtrlP": tcell.KeyCtrlP, "CtrlQ": tcell.KeyCtrlQ, "CtrlR": tcell.KeyCtrlR, "CtrlS": tcell.KeyCtrlS, "CtrlT": tcell.KeyCtrlT, "CtrlU": tcell.KeyCtrlU, "CtrlV": tcell.KeyCtrlV, "CtrlW": tcell.KeyCtrlW, "CtrlX": tcell.KeyCtrlX, "CtrlY": tcell.KeyCtrlY, "CtrlZ": tcell.KeyCtrlZ, "CtrlLeftSq": tcell.KeyCtrlLeftSq, "CtrlBackslash": tcell.KeyCtrlBackslash, "CtrlRightSq": tcell.KeyCtrlRightSq, "CtrlCarat": tcell.KeyCtrlCarat, "CtrlUnderscore": tcell.KeyCtrlUnderscore, "Tab": tcell.KeyTab, "Esc": tcell.KeyEsc, "Escape": tcell.KeyEscape, "Enter": tcell.KeyEnter, "Backspace": tcell.KeyBackspace2, "OldBackspace": tcell.KeyBackspace, // I renamed these keys to PageUp and PageDown but I don't want to break someone's keybindings "PgUp": tcell.KeyPgUp, "PgDown": tcell.KeyPgDn, } zyedidia-micro-6a62575/internal/action/actions_posix.go0000664000175000017510000000117315125206537022547 0ustar nileshnilesh//go:build linux || darwin || dragonfly || solaris || openbsd || netbsd || freebsd package action import ( "syscall" "github.com/zyedidia/micro/v2/internal/screen" ) // Suspend sends micro to the background. This is the same as pressing CtrlZ in most unix programs. // This only works on linux and has no default binding. // This code was adapted from the suspend code in nsf/godit func (*BufPane) Suspend() bool { screenb := screen.TempFini() // suspend the process pid := syscall.Getpid() err := syscall.Kill(pid, syscall.SIGSTOP) if err != nil { screen.TermMessage(err) } screen.TempStart(screenb) return false } zyedidia-micro-6a62575/internal/action/actions_other.go0000664000175000017510000000023715125206537022526 0ustar nileshnilesh//go:build plan9 || nacl || windows package action func (*BufPane) Suspend() bool { InfoBar.Error("Suspend is only supported on BSD/Linux") return false } zyedidia-micro-6a62575/internal/action/actions.go0000664000175000017510000016370715125206537021341 0ustar nileshnileshpackage action import ( "errors" "fmt" "io/fs" "os" "regexp" "runtime" "strings" "time" shellquote "github.com/kballard/go-shellquote" "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/clipboard" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/display" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/shell" "github.com/zyedidia/micro/v2/internal/util" ) // ScrollUp is not an action func (h *BufPane) ScrollUp(n int) { v := h.GetView() v.StartLine = h.Scroll(v.StartLine, -n) h.SetView(v) } // ScrollDown is not an action func (h *BufPane) ScrollDown(n int) { v := h.GetView() v.StartLine = h.Scroll(v.StartLine, n) h.SetView(v) } // ScrollAdjust can be used to shift the view so that the last line is at the // bottom if the user has scrolled past the last line. func (h *BufPane) ScrollAdjust() { v := h.GetView() end := h.SLocFromLoc(h.Buf.End()) if h.Diff(v.StartLine, end) < h.BufView().Height-1 { v.StartLine = h.Scroll(end, -h.BufView().Height+1) } h.SetView(v) } // ScrollReachedEnd returns true if the view is at the end of the buffer, // i.e. the last line of the buffer is in the view. func (h *BufPane) ScrollReachedEnd() bool { v := h.GetView() end := h.SLocFromLoc(h.Buf.End()) return h.Diff(v.StartLine, end) < h.BufView().Height } // MousePress is the event that should happen when a normal click happens // This is almost always bound to left click func (h *BufPane) MousePress(e *tcell.EventMouse) bool { b := h.Buf mx, my := e.Position() // ignore click on the status line if my >= h.BufView().Y+h.BufView().Height { return false } mouseLoc := h.LocFromVisual(buffer.Loc{mx, my}) h.Cursor.Loc = mouseLoc if b.NumCursors() > 1 { b.ClearCursors() h.Relocate() h.Cursor = h.Buf.GetActiveCursor() h.Cursor.Loc = mouseLoc } if time.Since(h.lastClickTime)/time.Millisecond < config.DoubleClickThreshold && (mouseLoc.X == h.lastLoc.X && mouseLoc.Y == h.lastLoc.Y) { if h.DoubleClick { // Triple click h.lastClickTime = time.Now() h.TripleClick = true h.DoubleClick = false h.Cursor.SelectLine() h.Cursor.CopySelection(clipboard.PrimaryReg) } else { // Double click h.lastClickTime = time.Now() h.DoubleClick = true h.TripleClick = false h.Cursor.SelectWord() h.Cursor.CopySelection(clipboard.PrimaryReg) } } else { h.DoubleClick = false h.TripleClick = false h.lastClickTime = time.Now() h.Cursor.OrigSelection[0] = h.Cursor.Loc h.Cursor.CurSelection[0] = h.Cursor.Loc h.Cursor.CurSelection[1] = h.Cursor.Loc } h.Cursor.StoreVisualX() h.lastLoc = mouseLoc h.Relocate() return true } func (h *BufPane) MouseDrag(e *tcell.EventMouse) bool { mx, my := e.Position() // ignore drag on the status line if my >= h.BufView().Y+h.BufView().Height { return false } h.Cursor.Loc = h.LocFromVisual(buffer.Loc{mx, my}) if h.TripleClick { h.Cursor.AddLineToSelection() } else if h.DoubleClick { h.Cursor.AddWordToSelection() } else { h.Cursor.SelectTo(h.Cursor.Loc) } h.Cursor.StoreVisualX() h.Relocate() return true } func (h *BufPane) MouseRelease(e *tcell.EventMouse) bool { // We could finish the selection based on the release location as in the // commented out code below, to allow text selections even in a terminal // that doesn't support mouse motion events. But when the mouse click is // within the scroll margin, that would cause a scroll and selection // even for a simple mouse click, which is not good. // if !h.DoubleClick && !h.TripleClick { // mx, my := e.Position() // h.Cursor.Loc = h.LocFromVisual(buffer.Loc{mx, my}) // h.Cursor.SetSelectionEnd(h.Cursor.Loc) // } if h.Cursor.HasSelection() { h.Cursor.CopySelection(clipboard.PrimaryReg) } return true } // ScrollUpAction scrolls the view up func (h *BufPane) ScrollUpAction() bool { h.ScrollUp(util.IntOpt(h.Buf.Settings["scrollspeed"])) return true } // ScrollDownAction scrolls the view down func (h *BufPane) ScrollDownAction() bool { h.ScrollDown(util.IntOpt(h.Buf.Settings["scrollspeed"])) return true } // Center centers the view on the cursor func (h *BufPane) Center() bool { v := h.GetView() v.StartLine = h.Scroll(h.SLocFromLoc(h.Cursor.Loc), -h.BufView().Height/2) h.SetView(v) h.ScrollAdjust() return true } // CursorToViewTop moves the cursor to the top of the view, // offset by scrollmargin unless at the beginning or end of the file func (h *BufPane) CursorToViewTop() bool { v := h.GetView() h.Buf.ClearCursors() scrollmargin := int(h.Buf.Settings["scrollmargin"].(float64)) bStart := display.SLoc{0, 0} if v.StartLine == bStart { scrollmargin = 0 } h.Cursor.GotoLoc(h.LocFromVLoc(display.VLoc{ SLoc: h.Scroll(v.StartLine, scrollmargin), VisualX: 0, })) return true } // CursorToViewCenter moves the cursor to the center of the view func (h *BufPane) CursorToViewCenter() bool { v := h.GetView() h.Buf.ClearCursors() h.Cursor.GotoLoc(h.LocFromVLoc(display.VLoc{ SLoc: h.Scroll(v.StartLine, h.BufView().Height/2), VisualX: 0, })) return true } // CursorToViewBottom moves the cursor to the bottom of the view, // offset by scrollmargin unless at the beginning or end of the file func (h *BufPane) CursorToViewBottom() bool { v := h.GetView() h.Buf.ClearCursors() scrollmargin := int(h.Buf.Settings["scrollmargin"].(float64)) bEnd := h.SLocFromLoc(h.Buf.End()) lastLine := h.Scroll(v.StartLine, h.BufView().Height-1) if lastLine == bEnd { scrollmargin = 0 } h.Cursor.GotoLoc(h.LocFromVLoc(display.VLoc{ SLoc: h.Scroll(lastLine, -scrollmargin), VisualX: 0, })) return true } // MoveCursorUp is not an action func (h *BufPane) MoveCursorUp(n int) { if !h.Buf.Settings["softwrap"].(bool) { h.Cursor.UpN(n) } else { vloc := h.VLocFromLoc(h.Cursor.Loc) sloc := h.Scroll(vloc.SLoc, -n) if sloc == vloc.SLoc { // we are at the beginning of buffer h.Cursor.Loc = h.Buf.Start() h.Cursor.StoreVisualX() } else { vloc.SLoc = sloc vloc.VisualX = h.Cursor.LastWrappedVisualX h.Cursor.Loc = h.LocFromVLoc(vloc) } } } // MoveCursorDown is not an action func (h *BufPane) MoveCursorDown(n int) { if !h.Buf.Settings["softwrap"].(bool) { h.Cursor.DownN(n) } else { vloc := h.VLocFromLoc(h.Cursor.Loc) sloc := h.Scroll(vloc.SLoc, n) if sloc == vloc.SLoc { // we are at the end of buffer h.Cursor.Loc = h.Buf.End() h.Cursor.StoreVisualX() } else { vloc.SLoc = sloc vloc.VisualX = h.Cursor.LastWrappedVisualX h.Cursor.Loc = h.LocFromVLoc(vloc) } } } // CursorUp moves the cursor up func (h *BufPane) CursorUp() bool { h.Cursor.Deselect(true) h.MoveCursorUp(1) h.Relocate() return true } // CursorDown moves the cursor down func (h *BufPane) CursorDown() bool { selectionEndNewline := h.Cursor.HasSelection() && h.Cursor.CurSelection[1].X == 0 h.Cursor.Deselect(false) if selectionEndNewline { h.Cursor.Start() } else { h.MoveCursorDown(1) } h.Relocate() return true } // CursorLeft moves the cursor left func (h *BufPane) CursorLeft() bool { if h.Cursor.HasSelection() { h.Cursor.Deselect(true) } else { tabstospaces := h.Buf.Settings["tabstospaces"].(bool) tabmovement := h.Buf.Settings["tabmovement"].(bool) if tabstospaces && tabmovement { tabsize := int(h.Buf.Settings["tabsize"].(float64)) line := h.Buf.LineBytes(h.Cursor.Y) if h.Cursor.X-tabsize >= 0 && util.IsSpaces(line[h.Cursor.X-tabsize:h.Cursor.X]) && util.IsBytesWhitespace(line[0:h.Cursor.X-tabsize]) { for i := 0; i < tabsize; i++ { h.Cursor.Left() } } else { h.Cursor.Left() } } else { h.Cursor.Left() } } h.Relocate() return true } // CursorRight moves the cursor right func (h *BufPane) CursorRight() bool { if h.Cursor.HasSelection() { h.Cursor.Deselect(false) } else { tabstospaces := h.Buf.Settings["tabstospaces"].(bool) tabmovement := h.Buf.Settings["tabmovement"].(bool) if tabstospaces && tabmovement { tabsize := int(h.Buf.Settings["tabsize"].(float64)) line := h.Buf.LineBytes(h.Cursor.Y) if h.Cursor.X+tabsize < util.CharacterCount(line) && util.IsSpaces(line[h.Cursor.X:h.Cursor.X+tabsize]) && util.IsBytesWhitespace(line[0:h.Cursor.X]) { for i := 0; i < tabsize; i++ { h.Cursor.Right() } } else { h.Cursor.Right() } } else { h.Cursor.Right() } } h.Relocate() return true } // WordRight moves the cursor one word to the right func (h *BufPane) WordRight() bool { h.Cursor.Deselect(false) h.Cursor.WordRight() h.Relocate() return true } // WordLeft moves the cursor one word to the left func (h *BufPane) WordLeft() bool { h.Cursor.Deselect(true) h.Cursor.WordLeft() h.Relocate() return true } // SubWordRight moves the cursor one sub-word to the right func (h *BufPane) SubWordRight() bool { h.Cursor.Deselect(false) h.Cursor.SubWordRight() h.Relocate() return true } // SubWordLeft moves the cursor one sub-word to the left func (h *BufPane) SubWordLeft() bool { h.Cursor.Deselect(true) h.Cursor.SubWordLeft() h.Relocate() return true } // SelectUp selects up one line func (h *BufPane) SelectUp() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.MoveCursorUp(1) h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectDown selects down one line func (h *BufPane) SelectDown() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.MoveCursorDown(1) h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectLeft selects the character to the left of the cursor func (h *BufPane) SelectLeft() bool { loc := h.Cursor.Loc count := h.Buf.End() if loc.GreaterThan(count) { loc = count } if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = loc } h.Cursor.Left() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectRight selects the character to the right of the cursor func (h *BufPane) SelectRight() bool { loc := h.Cursor.Loc count := h.Buf.End() if loc.GreaterThan(count) { loc = count } if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = loc } h.Cursor.Right() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectWordRight selects the word to the right of the cursor func (h *BufPane) SelectWordRight() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.Cursor.WordRight() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectWordLeft selects the word to the left of the cursor func (h *BufPane) SelectWordLeft() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.Cursor.WordLeft() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectSubWordRight selects the sub-word to the right of the cursor func (h *BufPane) SelectSubWordRight() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.Cursor.SubWordRight() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectSubWordLeft selects the sub-word to the left of the cursor func (h *BufPane) SelectSubWordLeft() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.Cursor.SubWordLeft() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // StartOfText moves the cursor to the start of the text of the line func (h *BufPane) StartOfText() bool { h.Cursor.Deselect(true) h.Cursor.StartOfText() h.Relocate() return true } // StartOfTextToggle toggles the cursor between the start of the text of the line // and the start of the line func (h *BufPane) StartOfTextToggle() bool { h.Cursor.Deselect(true) if h.Cursor.IsStartOfText() { h.Cursor.Start() } else { h.Cursor.StartOfText() } h.Relocate() return true } // StartOfLine moves the cursor to the start of the line func (h *BufPane) StartOfLine() bool { h.Cursor.Deselect(true) h.Cursor.Start() h.Relocate() return true } // EndOfLine moves the cursor to the end of the line func (h *BufPane) EndOfLine() bool { h.Cursor.Deselect(true) h.Cursor.End() h.Relocate() return true } // SelectLine selects the entire current line func (h *BufPane) SelectLine() bool { h.Cursor.SelectLine() h.Relocate() return true } // SelectToStartOfText selects to the start of the text on the current line func (h *BufPane) SelectToStartOfText() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.Cursor.StartOfText() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectToStartOfTextToggle toggles the selection between the start of the text // on the current line and the start of the line func (h *BufPane) SelectToStartOfTextToggle() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } if h.Cursor.IsStartOfText() { h.Cursor.Start() } else { h.Cursor.StartOfText() } h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectToStartOfLine selects to the start of the current line func (h *BufPane) SelectToStartOfLine() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.Cursor.Start() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectToEndOfLine selects to the end of the current line func (h *BufPane) SelectToEndOfLine() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.Cursor.End() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } func (h *BufPane) paragraphPrevious() { var line int // Skip to the first non-empty line for line = h.Cursor.Y; line > 0; line-- { if len(h.Buf.LineBytes(line)) != 0 { break } } // Find the first empty line for ; line > 0; line-- { if len(h.Buf.LineBytes(line)) == 0 { h.Cursor.X = 0 h.Cursor.Y = line break } } // If no empty line was found, move the cursor to the start of the buffer if line == 0 { h.Cursor.Loc = h.Buf.Start() } } func (h *BufPane) paragraphNext() { var line int // Skip to the first non-empty line for line = h.Cursor.Y; line < h.Buf.LinesNum(); line++ { if len(h.Buf.LineBytes(line)) != 0 { break } } // Find the first empty line for ; line < h.Buf.LinesNum(); line++ { if len(h.Buf.LineBytes(line)) == 0 { h.Cursor.X = 0 h.Cursor.Y = line break } } // If no empty line was found, move the cursor to the end of the buffer if line == h.Buf.LinesNum() { h.Cursor.Loc = h.Buf.End() } } // ParagraphPrevious moves the cursor to the first empty line that comes before // the paragraph closest to the cursor, or beginning of the buffer if there // isn't a paragraph func (h *BufPane) ParagraphPrevious() bool { h.Cursor.Deselect(true) h.paragraphPrevious() h.Relocate() return true } // ParagraphNext moves the cursor to the first empty line that comes after the // paragraph closest to the cursor, or end of the buffer if there isn't a // paragraph func (h *BufPane) ParagraphNext() bool { h.Cursor.Deselect(true) h.paragraphNext() h.Relocate() return true } // SelectToParagraphPrevious selects to the first empty line that comes before // the paragraph closest to the cursor, or beginning of the buffer if there // isn't a paragraph func (h *BufPane) SelectToParagraphPrevious() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.paragraphPrevious() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // SelectToParagraphNext selects to the first empty line that comes after the // paragraph closest to the cursor, or end of the buffer if there isn't a // paragraph func (h *BufPane) SelectToParagraphNext() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.paragraphNext() h.Cursor.SelectTo(h.Cursor.Loc) h.Relocate() return true } // Retab changes all tabs to spaces or all spaces to tabs depending // on the user's settings func (h *BufPane) Retab() bool { h.Buf.Retab() h.Relocate() return true } // CursorStart moves the cursor to the start of the buffer func (h *BufPane) CursorStart() bool { h.Cursor.Deselect(true) h.Cursor.X = 0 h.Cursor.Y = 0 h.Cursor.StoreVisualX() h.Relocate() return true } // CursorEnd moves the cursor to the end of the buffer func (h *BufPane) CursorEnd() bool { h.Cursor.Deselect(true) h.Cursor.Loc = h.Buf.End() h.Cursor.StoreVisualX() h.Relocate() return true } // SelectToStart selects the text from the cursor to the start of the buffer func (h *BufPane) SelectToStart() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.CursorStart() h.Cursor.SelectTo(h.Buf.Start()) h.Relocate() return true } // SelectToEnd selects the text from the cursor to the end of the buffer func (h *BufPane) SelectToEnd() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.CursorEnd() h.Cursor.SelectTo(h.Buf.End()) h.Relocate() return true } // InsertNewline inserts a newline plus possible some whitespace if autoindent is on func (h *BufPane) InsertNewline() bool { // Insert a newline if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() } ws := util.GetLeadingWhitespace(h.Buf.LineBytes(h.Cursor.Y)) cx := h.Cursor.X h.Buf.Insert(h.Cursor.Loc, "\n") // h.Cursor.Right() if h.Buf.Settings["autoindent"].(bool) { if cx < len(ws) { ws = ws[0:cx] } h.Buf.Insert(h.Cursor.Loc, string(ws)) // for i := 0; i < len(ws); i++ { // h.Cursor.Right() // } // Remove the whitespaces if keepautoindent setting is off if util.IsSpacesOrTabs(h.Buf.LineBytes(h.Cursor.Y-1)) && !h.Buf.Settings["keepautoindent"].(bool) { line := h.Buf.LineBytes(h.Cursor.Y - 1) h.Buf.Remove(buffer.Loc{X: 0, Y: h.Cursor.Y - 1}, buffer.Loc{X: util.CharacterCount(line), Y: h.Cursor.Y - 1}) } } h.Cursor.StoreVisualX() h.Relocate() return true } // Backspace deletes the previous character func (h *BufPane) Backspace() bool { if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() } else if h.Cursor.Loc.GreaterThan(h.Buf.Start()) { // We have to do something a bit hacky here because we want to // delete the line by first moving left and then deleting backwards // but the undo redo would place the cursor in the wrong place // So instead we move left, save the position, move back, delete // and restore the position // If the user is using spaces instead of tabs and they are deleting // whitespace at the start of the line, we should delete as if it's a // tab (tabSize number of spaces) lineStart := util.SliceStart(h.Buf.LineBytes(h.Cursor.Y), h.Cursor.X) tabSize := int(h.Buf.Settings["tabsize"].(float64)) if h.Buf.Settings["tabstospaces"].(bool) && util.IsSpaces(lineStart) && len(lineStart) != 0 && util.CharacterCount(lineStart)%tabSize == 0 { loc := h.Cursor.Loc h.Buf.Remove(loc.Move(-tabSize, h.Buf), loc) } else { loc := h.Cursor.Loc h.Buf.Remove(loc.Move(-1, h.Buf), loc) } } h.Cursor.StoreVisualX() h.Relocate() return true } // DeleteWordRight deletes the word to the right of the cursor func (h *BufPane) DeleteWordRight() bool { h.SelectWordRight() if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() } h.Relocate() return true } // DeleteWordLeft deletes the word to the left of the cursor func (h *BufPane) DeleteWordLeft() bool { h.SelectWordLeft() if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() } h.Relocate() return true } // DeleteSubWordRight deletes the sub-word to the right of the cursor func (h *BufPane) DeleteSubWordRight() bool { h.SelectSubWordRight() if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() } h.Relocate() return true } // DeleteSubWordLeft deletes the sub-word to the left of the cursor func (h *BufPane) DeleteSubWordLeft() bool { h.SelectSubWordLeft() if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() } h.Relocate() return true } // Delete deletes the next character func (h *BufPane) Delete() bool { if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() } else { loc := h.Cursor.Loc if loc.LessThan(h.Buf.End()) { h.Buf.Remove(loc, loc.Move(1, h.Buf)) } } h.Relocate() return true } // IndentSelection indents the current selection func (h *BufPane) IndentSelection() bool { if h.Cursor.HasSelection() { start := h.Cursor.CurSelection[0] end := h.Cursor.CurSelection[1] if end.Y < start.Y { start, end = end, start h.Cursor.SetSelectionStart(start) h.Cursor.SetSelectionEnd(end) } startY := start.Y endY := end.Move(-1, h.Buf).Y endX := end.Move(-1, h.Buf).X tabsize := int(h.Buf.Settings["tabsize"].(float64)) indentsize := len(h.Buf.IndentString(tabsize)) for y := startY; y <= endY; y++ { if len(h.Buf.LineBytes(y)) > 0 { h.Buf.Insert(buffer.Loc{X: 0, Y: y}, h.Buf.IndentString(tabsize)) if y == startY && start.X > 0 { h.Cursor.SetSelectionStart(start.Move(indentsize, h.Buf)) } if y == endY { h.Cursor.SetSelectionEnd(buffer.Loc{X: endX + indentsize + 1, Y: endY}) } } } h.Buf.RelocateCursors() h.Relocate() return true } return false } // IndentLine moves the current line forward one indentation func (h *BufPane) IndentLine() bool { if h.Cursor.HasSelection() { return false } tabsize := int(h.Buf.Settings["tabsize"].(float64)) indentstr := h.Buf.IndentString(tabsize) h.Buf.Insert(buffer.Loc{X: 0, Y: h.Cursor.Y}, indentstr) h.Buf.RelocateCursors() h.Relocate() return true } // OutdentLine moves the current line back one indentation func (h *BufPane) OutdentLine() bool { if h.Cursor.HasSelection() { return false } for x := 0; x < len(h.Buf.IndentString(util.IntOpt(h.Buf.Settings["tabsize"]))); x++ { if len(util.GetLeadingWhitespace(h.Buf.LineBytes(h.Cursor.Y))) == 0 { break } h.Buf.Remove(buffer.Loc{X: 0, Y: h.Cursor.Y}, buffer.Loc{X: 1, Y: h.Cursor.Y}) } h.Buf.RelocateCursors() h.Relocate() return true } // OutdentSelection takes the current selection and moves it back one indent level func (h *BufPane) OutdentSelection() bool { if h.Cursor.HasSelection() { start := h.Cursor.CurSelection[0] end := h.Cursor.CurSelection[1] if end.Y < start.Y { start, end = end, start h.Cursor.SetSelectionStart(start) h.Cursor.SetSelectionEnd(end) } startY := start.Y endY := end.Move(-1, h.Buf).Y for y := startY; y <= endY; y++ { for x := 0; x < len(h.Buf.IndentString(util.IntOpt(h.Buf.Settings["tabsize"]))); x++ { if len(util.GetLeadingWhitespace(h.Buf.LineBytes(y))) == 0 { break } h.Buf.Remove(buffer.Loc{X: 0, Y: y}, buffer.Loc{X: 1, Y: y}) } } h.Buf.RelocateCursors() h.Relocate() return true } return false } // Autocomplete cycles the suggestions and performs autocompletion if there are suggestions func (h *BufPane) Autocomplete() bool { b := h.Buf if h.Cursor.HasSelection() { return false } if b.HasSuggestions { b.CycleAutocomplete(true) return true } if h.Cursor.X == 0 { return false } r := h.Cursor.RuneUnder(h.Cursor.X) prev := h.Cursor.RuneUnder(h.Cursor.X - 1) if !util.IsAutocomplete(prev) || util.IsWordChar(r) { // don't autocomplete if cursor is within a word return false } return b.Autocomplete(buffer.BufferComplete) } // CycleAutocompleteBack cycles back in the autocomplete suggestion list func (h *BufPane) CycleAutocompleteBack() bool { if h.Cursor.HasSelection() { return false } if h.Buf.HasSuggestions { h.Buf.CycleAutocomplete(false) return true } return false } // InsertTab inserts a tab or spaces func (h *BufPane) InsertTab() bool { b := h.Buf indent := b.IndentString(util.IntOpt(b.Settings["tabsize"])) tabBytes := len(indent) bytesUntilIndent := tabBytes - (h.Cursor.GetVisualX(false) % tabBytes) b.Insert(h.Cursor.Loc, indent[:bytesUntilIndent]) h.Relocate() return true } // SaveAll saves all open buffers func (h *BufPane) SaveAll() bool { for _, b := range buffer.OpenBuffers { b.Save() } return true } // SaveCB performs a save and does a callback at the very end (after all prompts have been resolved) func (h *BufPane) SaveCB(action string, callback func()) bool { // If this is an empty buffer, ask for a filename if h.Buf.Path == "" { h.SaveAsCB(action, callback) } else { noPrompt := h.saveBufToFile(h.Buf.Path, action, callback) if noPrompt { return true } } return false } // Save the buffer to disk func (h *BufPane) Save() bool { return h.SaveCB("Save", nil) } // SaveAsCB performs a save as and does a callback at the very end (after all prompts have been resolved) // The callback is only called if the save was successful func (h *BufPane) SaveAsCB(action string, callback func()) bool { InfoBar.Prompt("Filename: ", "", "Save", nil, func(resp string, canceled bool) { if !canceled { // the filename might or might not be quoted, so unquote first then join the strings. args, err := shellquote.Split(resp) if err != nil { InfoBar.Error("Error parsing arguments: ", err) return } if len(args) == 0 { InfoBar.Error("No filename given") return } filename := strings.Join(args, " ") fileinfo, err := os.Stat(filename) if err != nil { if errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrPermission) { noPrompt := h.saveBufToFile(filename, action, callback) if noPrompt { h.completeAction(action) return } } else { InfoBar.Error(err) return } } else { InfoBar.YNPrompt( fmt.Sprintf("The file %s already exists in the directory, would you like to overwrite? Y/n", fileinfo.Name()), func(yes, canceled bool) { if yes && !canceled { noPrompt := h.saveBufToFile(filename, action, callback) if noPrompt { h.completeAction(action) } } }, ) } } }) return false } // SaveAs saves the buffer to disk with the given name func (h *BufPane) SaveAs() bool { return h.SaveAsCB("SaveAs", nil) } // This function saves the buffer to `filename` and changes the buffer's path and name // to `filename` if the save is successful // The callback is only called if the save was successful func (h *BufPane) saveBufToFile(filename string, action string, callback func()) bool { err := h.Buf.SaveAs(filename) if err != nil { if errors.Is(err, fs.ErrPermission) { if runtime.GOOS == "windows" { InfoBar.Error("Permission denied. Save with sudo not supported on Windows") return true } saveWithSudo := func() { err = h.Buf.SaveAsWithSudo(filename) if err != nil { InfoBar.Error(err) } else { InfoBar.Message("Saved " + filename) if callback != nil { callback() } } } if h.Buf.Settings["autosu"].(bool) { saveWithSudo() } else { InfoBar.YNPrompt( fmt.Sprintf("Permission denied. Do you want to save this file using %s? (y,n)", config.GlobalSettings["sucmd"].(string)), func(yes, canceled bool) { if yes && !canceled { saveWithSudo() h.completeAction(action) } }, ) return false } } else { InfoBar.Error(err) } } else { InfoBar.Message("Saved " + filename) if callback != nil { callback() } } return true } // Find opens a prompt and searches forward for the input func (h *BufPane) Find() bool { return h.find(true) } // FindLiteral is the same as Find() but does not support regular expressions func (h *BufPane) FindLiteral() bool { return h.find(false) } // Search searches for a given string/regex in the buffer and selects the next // match if a match is found // This function behaves the same way as Find and FindLiteral actions: // it affects the buffer's LastSearch and LastSearchRegex (saved searches) // for use with FindNext and FindPrevious, and turns HighlightSearch on or off // according to hlsearch setting func (h *BufPane) Search(str string, useRegex bool, searchDown bool) error { match, found, err := h.Buf.FindNext(str, h.Buf.Start(), h.Buf.End(), h.Cursor.Loc, searchDown, useRegex) if err != nil { return err } if found { h.Cursor.SetSelectionStart(match[0]) h.Cursor.SetSelectionEnd(match[1]) h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0] h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1] h.GotoLoc(h.Cursor.CurSelection[1]) h.Buf.LastSearch = str h.Buf.LastSearchRegex = useRegex h.Buf.HighlightSearch = h.Buf.Settings["hlsearch"].(bool) } else { h.Cursor.ResetSelection() } return nil } func (h *BufPane) find(useRegex bool) bool { h.searchOrig = h.Cursor.Loc prompt := "Find: " if useRegex { prompt = "Find (regex): " } var eventCallback func(resp string) if h.Buf.Settings["incsearch"].(bool) { eventCallback = func(resp string) { match, found, _ := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, useRegex) if found { h.Cursor.SetSelectionStart(match[0]) h.Cursor.SetSelectionEnd(match[1]) h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0] h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1] h.GotoLoc(match[1]) } else { h.GotoLoc(h.searchOrig) h.Cursor.ResetSelection() } } } findCallback := func(resp string, canceled bool) { // Finished callback if !canceled { match, found, err := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, useRegex) if err != nil { InfoBar.Error(err) } else if found { h.Cursor.SetSelectionStart(match[0]) h.Cursor.SetSelectionEnd(match[1]) h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0] h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1] h.GotoLoc(h.Cursor.CurSelection[1]) h.Buf.LastSearch = resp h.Buf.LastSearchRegex = useRegex h.Buf.HighlightSearch = h.Buf.Settings["hlsearch"].(bool) } else { h.Cursor.ResetSelection() InfoBar.Message("No matches found") } } else { h.Cursor.ResetSelection() } } pattern := string(h.Cursor.GetSelection()) if useRegex && pattern != "" { pattern = regexp.QuoteMeta(pattern) } if eventCallback != nil && pattern != "" { eventCallback(pattern) } InfoBar.Prompt(prompt, pattern, "Find", eventCallback, findCallback) if pattern != "" { InfoBar.SelectAll() } return true } // ToggleHighlightSearch toggles highlighting all instances of the last used search term func (h *BufPane) ToggleHighlightSearch() bool { h.Buf.HighlightSearch = !h.Buf.HighlightSearch return true } // UnhighlightSearch unhighlights all instances of the last used search term func (h *BufPane) UnhighlightSearch() bool { if !h.Buf.HighlightSearch { return false } h.Buf.HighlightSearch = false return true } // ResetSearch resets the last used search term func (h *BufPane) ResetSearch() bool { if h.Buf.LastSearch != "" { h.Buf.LastSearch = "" return true } return false } // FindNext searches forwards for the last used search term func (h *BufPane) FindNext() bool { if h.Buf.LastSearch == "" { return false } // If the cursor is at the start of a selection and we search we want // to search from the end of the selection in the case that // the selection is a search result in which case we wouldn't move at // at all which would be bad searchLoc := h.Cursor.Loc if h.Cursor.HasSelection() { searchLoc = h.Cursor.CurSelection[1] } match, found, err := h.Buf.FindNext(h.Buf.LastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, true, h.Buf.LastSearchRegex) if err != nil { InfoBar.Error(err) } else if found && searchLoc == match[0] && match[0] == match[1] { // skip empty match at present cursor location if searchLoc == h.Buf.End() { searchLoc = h.Buf.Start() } else { searchLoc = searchLoc.Move(1, h.Buf) } match, found, _ = h.Buf.FindNext(h.Buf.LastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, true, h.Buf.LastSearchRegex) } if found { h.Cursor.SetSelectionStart(match[0]) h.Cursor.SetSelectionEnd(match[1]) h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0] h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1] h.GotoLoc(h.Cursor.CurSelection[1]) } else { h.Cursor.ResetSelection() } return true } // FindPrevious searches backwards for the last used search term func (h *BufPane) FindPrevious() bool { if h.Buf.LastSearch == "" { return false } // If the cursor is at the end of a selection and we search we want // to search from the beginning of the selection in the case that // the selection is a search result in which case we wouldn't move at // at all which would be bad searchLoc := h.Cursor.Loc if h.Cursor.HasSelection() { searchLoc = h.Cursor.CurSelection[0] } match, found, err := h.Buf.FindNext(h.Buf.LastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, false, h.Buf.LastSearchRegex) if err != nil { InfoBar.Error(err) } else if found && searchLoc == match[0] && match[0] == match[1] { // skip empty match at present cursor location if searchLoc == h.Buf.Start() { searchLoc = h.Buf.End() } else { searchLoc = searchLoc.Move(-1, h.Buf) } match, found, _ = h.Buf.FindNext(h.Buf.LastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, false, h.Buf.LastSearchRegex) } if found { h.Cursor.SetSelectionStart(match[0]) h.Cursor.SetSelectionEnd(match[1]) h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0] h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1] h.GotoLoc(h.Cursor.CurSelection[1]) } else { h.Cursor.ResetSelection() } return true } // DiffNext searches forward until the beginning of the next block of diffs func (h *BufPane) DiffNext() bool { cur := h.Cursor.Loc.Y dl, err := h.Buf.FindNextDiffLine(cur, true) if err != nil { return false } h.GotoLoc(buffer.Loc{0, dl}) return true } // DiffPrevious searches forward until the end of the previous block of diffs func (h *BufPane) DiffPrevious() bool { cur := h.Cursor.Loc.Y dl, err := h.Buf.FindNextDiffLine(cur, false) if err != nil { return false } h.GotoLoc(buffer.Loc{0, dl}) return true } // Undo undoes the last action func (h *BufPane) Undo() bool { if !h.Buf.Undo() { return false } InfoBar.Message("Undid action") h.Relocate() return true } // Redo redoes the last action func (h *BufPane) Redo() bool { if !h.Buf.Redo() { return false } InfoBar.Message("Redid action") h.Relocate() return true } func (h *BufPane) selectLines() int { if h.Cursor.HasSelection() { start := h.Cursor.CurSelection[0] end := h.Cursor.CurSelection[1] if start.GreaterThan(end) { start, end = end, start } if end.X == 0 { end = end.Move(-1, h.Buf) } h.Cursor.Deselect(true) h.Cursor.SetSelectionStart(buffer.Loc{0, start.Y}) h.Cursor.SetSelectionEnd(buffer.Loc{0, end.Y + 1}) } else { h.Cursor.SelectLine() } nlines := h.Cursor.CurSelection[1].Y - h.Cursor.CurSelection[0].Y if nlines == 0 && h.Cursor.HasSelection() { // selected last line and it is not empty nlines++ } return nlines } // Copy the selection to the system clipboard func (h *BufPane) Copy() bool { if !h.Cursor.HasSelection() { return false } h.Cursor.CopySelection(clipboard.ClipboardReg) h.freshClip = false InfoBar.Message("Copied selection") h.Relocate() return true } // CopyLine copies the current line to the clipboard. If there is a selection, // CopyLine copies all the lines that are (fully or partially) in the selection. func (h *BufPane) CopyLine() bool { origLoc := h.Cursor.Loc origLastVisualX := h.Cursor.LastVisualX origLastWrappedVisualX := h.Cursor.LastWrappedVisualX origSelection := h.Cursor.CurSelection nlines := h.selectLines() if nlines == 0 { return false } h.Cursor.CopySelection(clipboard.ClipboardReg) h.freshClip = false if nlines > 1 { InfoBar.Message(fmt.Sprintf("Copied %d lines", nlines)) } else { InfoBar.Message("Copied line") } h.Cursor.Loc = origLoc h.Cursor.LastVisualX = origLastVisualX h.Cursor.LastWrappedVisualX = origLastWrappedVisualX h.Cursor.CurSelection = origSelection h.Relocate() return true } // Cut the selection to the system clipboard func (h *BufPane) Cut() bool { if !h.Cursor.HasSelection() { return false } h.Cursor.CopySelection(clipboard.ClipboardReg) h.Cursor.DeleteSelection() h.Cursor.ResetSelection() h.freshClip = false InfoBar.Message("Cut selection") h.Relocate() return true } // CutLine cuts the current line to the clipboard. If there is a selection, // CutLine cuts all the lines that are (fully or partially) in the selection. func (h *BufPane) CutLine() bool { nlines := h.selectLines() if nlines == 0 { return false } totalLines := nlines if h.freshClip { if clip, err := clipboard.Read(clipboard.ClipboardReg); err != nil { InfoBar.Error(err) return false } else { clipboard.WriteMulti(clip+string(h.Cursor.GetSelection()), clipboard.ClipboardReg, h.Cursor.Num, h.Buf.NumCursors()) totalLines = strings.Count(clip, "\n") + nlines } } else { h.Cursor.CopySelection(clipboard.ClipboardReg) } h.freshClip = true h.Cursor.DeleteSelection() h.Cursor.ResetSelection() h.Cursor.StoreVisualX() if totalLines > 1 { InfoBar.Message(fmt.Sprintf("Cut %d lines", totalLines)) } else { InfoBar.Message("Cut line") } h.Relocate() return true } // Duplicate the selection func (h *BufPane) Duplicate() bool { if !h.Cursor.HasSelection() { return false } h.Buf.Insert(h.Cursor.CurSelection[1], string(h.Cursor.GetSelection())) InfoBar.Message("Duplicated selection") h.Relocate() return true } // DuplicateLine duplicates the current line. If there is a selection, DuplicateLine // duplicates all the lines that are (fully or partially) in the selection. func (h *BufPane) DuplicateLine() bool { if h.Cursor.HasSelection() { origLoc := h.Cursor.Loc origLastVisualX := h.Cursor.LastVisualX origLastWrappedVisualX := h.Cursor.LastWrappedVisualX origSelection := h.Cursor.CurSelection start := h.Cursor.CurSelection[0] end := h.Cursor.CurSelection[1] if start.GreaterThan(end) { start, end = end, start } if end.X == 0 { end = end.Move(-1, h.Buf) } h.Cursor.Deselect(true) h.Cursor.Loc = end h.Cursor.End() for y := start.Y; y <= end.Y; y++ { h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(y))) } h.Cursor.Loc = origLoc h.Cursor.LastVisualX = origLastVisualX h.Cursor.LastWrappedVisualX = origLastWrappedVisualX h.Cursor.CurSelection = origSelection if start.Y < end.Y { InfoBar.Message(fmt.Sprintf("Duplicated %d lines", end.Y-start.Y+1)) } else { InfoBar.Message("Duplicated line") } } else { h.Cursor.End() h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(h.Cursor.Y))) InfoBar.Message("Duplicated line") } h.Relocate() return true } // DeleteLine deletes the current line. If there is a selection, DeleteLine // deletes all the lines that are (fully or partially) in the selection. func (h *BufPane) DeleteLine() bool { nlines := h.selectLines() if nlines == 0 { return false } h.Cursor.DeleteSelection() h.Cursor.ResetSelection() h.Cursor.StoreVisualX() if nlines > 1 { InfoBar.Message(fmt.Sprintf("Deleted %d lines", nlines)) } else { InfoBar.Message("Deleted line") } h.Relocate() return true } // MoveLinesUp moves up the current line or selected lines if any func (h *BufPane) MoveLinesUp() bool { if h.Cursor.HasSelection() { if h.Cursor.CurSelection[0].Y == 0 { InfoBar.Message("Cannot move further up") return false } start := h.Cursor.CurSelection[0].Y end := h.Cursor.CurSelection[1].Y sel := 1 if start > end { end, start = start, end sel = 0 } compensate := false if h.Cursor.CurSelection[sel].X != 0 { end++ } else { compensate = true } h.Buf.MoveLinesUp( start, end, ) if compensate { h.Cursor.CurSelection[sel].Y -= 1 } } else { if h.Cursor.Loc.Y == 0 { InfoBar.Message("Cannot move further up") return false } h.Buf.MoveLinesUp( h.Cursor.Loc.Y, h.Cursor.Loc.Y+1, ) } h.Relocate() return true } // MoveLinesDown moves down the current line or selected lines if any func (h *BufPane) MoveLinesDown() bool { if h.Cursor.HasSelection() { if h.Cursor.CurSelection[1].Y >= h.Buf.LinesNum() { InfoBar.Message("Cannot move further down") return false } start := h.Cursor.CurSelection[0].Y end := h.Cursor.CurSelection[1].Y sel := 1 if start > end { end, start = start, end sel = 0 } if h.Cursor.CurSelection[sel].X != 0 { end++ } h.Buf.MoveLinesDown( start, end, ) } else { if h.Cursor.Loc.Y >= h.Buf.LinesNum()-1 { InfoBar.Message("Cannot move further down") return false } h.Buf.MoveLinesDown( h.Cursor.Loc.Y, h.Cursor.Loc.Y+1, ) } h.Relocate() return true } // Paste whatever is in the system clipboard into the buffer // Delete and paste if the user has a selection func (h *BufPane) Paste() bool { clip, err := clipboard.ReadMulti(clipboard.ClipboardReg, h.Cursor.Num, h.Buf.NumCursors()) if err != nil { InfoBar.Error(err) } else { h.paste(clip) } h.Relocate() return true } // PastePrimary pastes from the primary clipboard (only use on linux) func (h *BufPane) PastePrimary() bool { clip, err := clipboard.ReadMulti(clipboard.PrimaryReg, h.Cursor.Num, h.Buf.NumCursors()) if err != nil { InfoBar.Error(err) } else { h.paste(clip) } h.Relocate() return true } func (h *BufPane) paste(clip string) { if h.Buf.Settings["smartpaste"].(bool) { if h.Cursor.X > 0 { leadingPasteWS := string(util.GetLeadingWhitespace([]byte(clip))) if leadingPasteWS != " " && strings.Contains(clip, "\n"+leadingPasteWS) { leadingWS := string(util.GetLeadingWhitespace(h.Buf.LineBytes(h.Cursor.Y))) clip = strings.TrimPrefix(clip, leadingPasteWS) clip = strings.ReplaceAll(clip, "\n"+leadingPasteWS, "\n"+leadingWS) } } } if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() } h.Buf.Insert(h.Cursor.Loc, clip) // h.Cursor.Loc = h.Cursor.Loc.Move(Count(clip), h.Buf) h.freshClip = false InfoBar.Message("Pasted clipboard") } // JumpToMatchingBrace moves the cursor to the matching brace if it is // currently on a brace func (h *BufPane) JumpToMatchingBrace() bool { matchingBrace, left, found := h.Buf.FindMatchingBrace(h.Cursor.Loc) if found { if h.Buf.Settings["matchbraceleft"].(bool) { if left { h.Cursor.GotoLoc(matchingBrace) } else { h.Cursor.GotoLoc(matchingBrace.Move(1, h.Buf)) } } else { h.Cursor.GotoLoc(matchingBrace) } h.Relocate() return true } return false } // SelectAll selects the entire buffer func (h *BufPane) SelectAll() bool { h.Cursor.SetSelectionStart(h.Buf.Start()) h.Cursor.SetSelectionEnd(h.Buf.End()) // Put the cursor at the beginning h.Cursor.X = 0 h.Cursor.Y = 0 h.Relocate() return true } // OpenFile opens a new file in the buffer func (h *BufPane) OpenFile() bool { InfoBar.Prompt("> ", "open ", "Open", nil, func(resp string, canceled bool) { if !canceled { h.HandleCommand(resp) } }) return true } // JumpLine asks the user to enter a line number to jump to func (h *BufPane) JumpLine() bool { InfoBar.Prompt("> ", "goto ", "Command", nil, func(resp string, canceled bool) { if !canceled { h.HandleCommand(resp) } }) return true } // Start moves the viewport to the start of the buffer func (h *BufPane) Start() bool { v := h.GetView() v.StartLine = display.SLoc{0, 0} h.SetView(v) return true } // End moves the viewport to the end of the buffer func (h *BufPane) End() bool { v := h.GetView() v.StartLine = h.Scroll(h.SLocFromLoc(h.Buf.End()), -h.BufView().Height+1) h.SetView(v) return true } // PageUp scrolls the view up a page func (h *BufPane) PageUp() bool { pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64)) h.ScrollUp(h.BufView().Height - pageOverlap) return true } // PageDown scrolls the view down a page func (h *BufPane) PageDown() bool { pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64)) h.ScrollDown(h.BufView().Height - pageOverlap) h.ScrollAdjust() return true } // SelectPageUp selects up one page func (h *BufPane) SelectPageUp() bool { pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64)) scrollAmount := h.BufView().Height - pageOverlap if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.MoveCursorUp(scrollAmount) h.Cursor.SelectTo(h.Cursor.Loc) if h.Cursor.Num == 0 { h.ScrollUp(scrollAmount) } h.Relocate() return true } // SelectPageDown selects down one page func (h *BufPane) SelectPageDown() bool { pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64)) scrollAmount := h.BufView().Height - pageOverlap if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } h.MoveCursorDown(scrollAmount) h.Cursor.SelectTo(h.Cursor.Loc) if h.Cursor.Num == 0 && !h.ScrollReachedEnd() { h.ScrollDown(scrollAmount) h.ScrollAdjust() } h.Relocate() return true } // CursorPageUp places the cursor a page up, // moving the view to keep cursor at the same relative position in the view func (h *BufPane) CursorPageUp() bool { h.Cursor.Deselect(true) pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64)) scrollAmount := h.BufView().Height - pageOverlap h.MoveCursorUp(scrollAmount) if h.Cursor.Num == 0 { h.ScrollUp(scrollAmount) } h.Relocate() return true } // CursorPageDown places the cursor a page down, // moving the view to keep cursor at the same relative position in the view func (h *BufPane) CursorPageDown() bool { selectionEndNewline := h.Cursor.HasSelection() && h.Cursor.CurSelection[1].X == 0 h.Cursor.Deselect(false) pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64)) scrollAmount := h.BufView().Height - pageOverlap if selectionEndNewline { scrollAmount-- } h.MoveCursorDown(scrollAmount) if h.Cursor.Num == 0 && !h.ScrollReachedEnd() { h.ScrollDown(scrollAmount) h.ScrollAdjust() } if selectionEndNewline { h.Cursor.Start() } h.Relocate() return true } // HalfPageUp scrolls the view up half a page func (h *BufPane) HalfPageUp() bool { h.ScrollUp(h.BufView().Height / 2) return true } // HalfPageDown scrolls the view down half a page func (h *BufPane) HalfPageDown() bool { h.ScrollDown(h.BufView().Height / 2) h.ScrollAdjust() return true } // ToggleDiffGutter turns the diff gutter off and on func (h *BufPane) ToggleDiffGutter() bool { diffgutter := !h.Buf.Settings["diffgutter"].(bool) h.Buf.SetOptionNative("diffgutter", diffgutter) if diffgutter { h.Buf.UpdateDiff() InfoBar.Message("Enabled diff gutter") } else { InfoBar.Message("Disabled diff gutter") } return true } // ToggleRuler turns line numbers off and on func (h *BufPane) ToggleRuler() bool { ruler := !h.Buf.Settings["ruler"].(bool) h.Buf.SetOptionNative("ruler", ruler) if ruler { InfoBar.Message("Enabled ruler") } else { InfoBar.Message("Disabled ruler") } return true } // ClearStatus clears the infobar. It is an alias for ClearInfo. func (h *BufPane) ClearStatus() bool { return h.ClearInfo() } // ToggleHelp toggles the help screen func (h *BufPane) ToggleHelp() bool { if h.Buf.Type == buffer.BTHelp { h.Quit() } else { hsplit := config.GlobalSettings["helpsplit"] == "hsplit" h.openHelp("help", hsplit, false) } return true } // ToggleKeyMenu toggles the keymenu option and resizes all tabs func (h *BufPane) ToggleKeyMenu() bool { config.GlobalSettings["keymenu"] = !config.GetGlobalOption("keymenu").(bool) Tabs.Resize() return true } // ShellMode opens a terminal to run a shell command func (h *BufPane) ShellMode() bool { InfoBar.Prompt("$ ", "", "Shell", nil, func(resp string, canceled bool) { if !canceled { // The true here is for openTerm to make the command interactive shell.RunInteractiveShell(resp, true, false) } }) return true } // CommandMode lets the user enter a command func (h *BufPane) CommandMode() bool { InfoBar.Prompt("> ", "", "Command", nil, func(resp string, canceled bool) { if !canceled { h.HandleCommand(resp) } }) return true } // ToggleOverwriteMode lets the user toggle the text overwrite mode func (h *BufPane) ToggleOverwriteMode() bool { h.Buf.OverwriteMode = !h.Buf.OverwriteMode return true } // Escape leaves current mode func (h *BufPane) Escape() bool { return true } // Deselect deselects on the current cursor func (h *BufPane) Deselect() bool { if !h.Cursor.HasSelection() { return false } h.Cursor.Deselect(true) return true } // ClearInfo clears the infobar func (h *BufPane) ClearInfo() bool { if InfoBar.Msg == "" { return false } InfoBar.Message("") return true } // ForceQuit closes the tab or view even if there are unsaved changes // (no prompt) func (h *BufPane) ForceQuit() bool { h.Buf.Close() if len(h.tab.Panes) > 1 { h.Unsplit() } else if len(Tabs.List) > 1 { Tabs.RemoveTab(h.splitID) } else { screen.Screen.Fini() InfoBar.Close() runtime.Goexit() } return true } // closePrompt displays a prompt to save the buffer before closing it to proceed // with a different action or command func (h *BufPane) closePrompt(action string, callback func()) { InfoBar.YNPrompt("Save changes to "+h.Buf.GetName()+" before closing? (y,n,esc)", func(yes, canceled bool) { if !canceled && !yes { callback() } else if !canceled && yes { h.SaveCB(action, callback) } }) } // Quit this will close the current tab or view that is open func (h *BufPane) Quit() bool { if h.Buf.Modified() && !h.Buf.Shared() { if config.GlobalSettings["autosave"].(float64) > 0 && h.Buf.Path != "" { // autosave on means we automatically save when quitting h.SaveCB("Quit", func() { h.ForceQuit() }) } else { h.closePrompt("Quit", func() { h.ForceQuit() }) } } else { h.ForceQuit() } return true } // QuitAll quits the whole editor; all splits and tabs func (h *BufPane) QuitAll() bool { anyModified := false for _, b := range buffer.OpenBuffers { if b.Modified() { anyModified = true break } } quit := func() { buffer.CloseOpenBuffers() screen.Screen.Fini() InfoBar.Close() runtime.Goexit() } if anyModified { InfoBar.YNPrompt("Quit micro? (all open buffers will be closed without saving)", func(yes, canceled bool) { if !canceled && yes { quit() } }) } else { quit() } return true } // AddTab adds a new tab with an empty buffer func (h *BufPane) AddTab() bool { width, height := screen.Screen.Size() iOffset := config.GetInfoBarOffset() b := buffer.NewBufferFromString("", "", buffer.BTDefault) tp := NewTabFromBuffer(0, 0, width, height-iOffset, b) Tabs.AddTab(tp) Tabs.SetActive(len(Tabs.List) - 1) return true } // PreviousTab switches to the previous tab in the tab list func (h *BufPane) PreviousTab() bool { if Tabs.Active() == 0 { return false } Tabs.SetActive(Tabs.Active() - 1) return true } // NextTab switches to the next tab in the tab list func (h *BufPane) NextTab() bool { if Tabs.Active() == len(Tabs.List)-1 { return false } Tabs.SetActive(Tabs.Active() + 1) return true } // FirstTab switches to the first tab in the tab list func (h *BufPane) FirstTab() bool { if Tabs.Active() == 0 { return false } Tabs.SetActive(0) return true } // LastTab switches to the last tab in the tab list func (h *BufPane) LastTab() bool { lastTabIndex := len(Tabs.List) - 1 if Tabs.Active() == lastTabIndex { return false } Tabs.SetActive(lastTabIndex) return true } // VSplitAction opens an empty vertical split func (h *BufPane) VSplitAction() bool { h.VSplitBuf(buffer.NewBufferFromString("", "", buffer.BTDefault)) return true } // HSplitAction opens an empty horizontal split func (h *BufPane) HSplitAction() bool { h.HSplitBuf(buffer.NewBufferFromString("", "", buffer.BTDefault)) return true } // Unsplit closes all splits in the current tab except the active one func (h *BufPane) Unsplit() bool { tab := h.tab n := tab.GetNode(h.splitID) ok := n.Unsplit() if ok { tab.RemovePane(tab.GetPane(h.splitID)) tab.Resize() tab.SetActive(len(tab.Panes) - 1) return true } return false } // NextSplit changes the view to the next split func (h *BufPane) NextSplit() bool { if h.tab.active == len(h.tab.Panes)-1 { return false } h.tab.SetActive(h.tab.active + 1) return true } // PreviousSplit changes the view to the previous split func (h *BufPane) PreviousSplit() bool { if h.tab.active == 0 { return false } h.tab.SetActive(h.tab.active - 1) return true } // FirstSplit changes the view to the first split func (h *BufPane) FirstSplit() bool { if h.tab.active == 0 { return false } h.tab.SetActive(0) return true } // LastSplit changes the view to the last split func (h *BufPane) LastSplit() bool { lastPaneIdx := len(h.tab.Panes) - 1 if h.tab.active == lastPaneIdx { return false } h.tab.SetActive(lastPaneIdx) return true } var curmacro []any var recordingMacro bool // ToggleMacro toggles recording of a macro func (h *BufPane) ToggleMacro() bool { recordingMacro = !recordingMacro if recordingMacro { curmacro = []any{} InfoBar.Message("Recording") } else { InfoBar.Message("Stopped recording") } h.Relocate() return true } // PlayMacro plays back the most recently recorded macro func (h *BufPane) PlayMacro() bool { if recordingMacro { return false } for _, action := range curmacro { switch t := action.(type) { case rune: h.DoRuneInsert(t) case BufKeyAction: t(h) } } h.Relocate() return true } // SpawnMultiCursor creates a new multiple cursor at the next occurrence of the current selection or current word func (h *BufPane) SpawnMultiCursor() bool { spawner := h.Buf.GetCursor(h.Buf.NumCursors() - 1) if !spawner.HasSelection() { spawner.SelectWord() h.multiWord = true h.Relocate() return true } sel := spawner.GetSelection() searchStart := spawner.CurSelection[1] search := string(sel) search = regexp.QuoteMeta(search) if h.multiWord { search = "\\b" + search + "\\b" } match, found, err := h.Buf.FindNext(search, h.Buf.Start(), h.Buf.End(), searchStart, true, true) if err != nil { InfoBar.Error(err) } if found { c := buffer.NewCursor(h.Buf, buffer.Loc{}) c.SetSelectionStart(match[0]) c.SetSelectionEnd(match[1]) c.OrigSelection[0] = c.CurSelection[0] c.OrigSelection[1] = c.CurSelection[1] c.Loc = c.CurSelection[1] h.Buf.AddCursor(c) h.Buf.SetCurCursor(h.Buf.NumCursors() - 1) h.Buf.MergeCursors() } else { InfoBar.Message("No matches found") } h.Relocate() return true } // SpawnCursorAtLoc spawns a new cursor at a location and merges the cursors func (h *BufPane) SpawnCursorAtLoc(loc buffer.Loc) *buffer.Cursor { c := buffer.NewCursor(h.Buf, loc) h.Buf.AddCursor(c) h.Buf.MergeCursors() return c } // SpawnMultiCursorUpN is not an action func (h *BufPane) SpawnMultiCursorUpN(n int) bool { lastC := h.Buf.GetCursor(h.Buf.NumCursors() - 1) if n > 0 && lastC.Y == 0 { return false } if n < 0 && lastC.Y+1 == h.Buf.LinesNum() { return false } h.Buf.DeselectCursors() c := buffer.NewCursor(h.Buf, buffer.Loc{lastC.X, lastC.Y - n}) c.LastVisualX = lastC.LastVisualX c.LastWrappedVisualX = lastC.LastWrappedVisualX c.X = c.GetCharPosInLine(h.Buf.LineBytes(c.Y), c.LastVisualX) c.Relocate() h.Buf.AddCursor(c) h.Buf.SetCurCursor(h.Buf.NumCursors() - 1) h.Buf.MergeCursors() h.Relocate() return true } // SpawnMultiCursorUp creates additional cursor, at the same X (if possible), one Y less. func (h *BufPane) SpawnMultiCursorUp() bool { return h.SpawnMultiCursorUpN(1) } // SpawnMultiCursorDown creates additional cursor, at the same X (if possible), one Y more. func (h *BufPane) SpawnMultiCursorDown() bool { return h.SpawnMultiCursorUpN(-1) } // SpawnMultiCursorSelect adds a cursor at the beginning of each line of a selection func (h *BufPane) SpawnMultiCursorSelect() bool { // Avoid cases where multiple cursors already exist, that would create problems if h.Buf.NumCursors() > 1 { return false } var startLine int var endLine int a, b := h.Cursor.CurSelection[0].Y, h.Cursor.CurSelection[1].Y if a > b { startLine, endLine = b, a } else { startLine, endLine = a, b } if h.Cursor.HasSelection() { h.Cursor.ResetSelection() h.Cursor.GotoLoc(buffer.Loc{0, startLine}) for i := startLine; i <= endLine; i++ { c := buffer.NewCursor(h.Buf, buffer.Loc{0, i}) c.StoreVisualX() h.Buf.AddCursor(c) } h.Buf.MergeCursors() } else { return false } InfoBar.Message("Added cursors from selection") return true } // MouseMultiCursor is a mouse action which puts a new cursor at the mouse position, // or removes a cursor if it is already there func (h *BufPane) MouseMultiCursor(e *tcell.EventMouse) bool { b := h.Buf mx, my := e.Position() // ignore click on the status line if my >= h.BufView().Y+h.BufView().Height { return false } mouseLoc := h.LocFromVisual(buffer.Loc{X: mx, Y: my}) if h.Buf.NumCursors() > 1 { cursors := h.Buf.GetCursors() for _, c := range cursors { if c.Loc == mouseLoc { h.Buf.RemoveCursor(c.Num) return true } } } c := buffer.NewCursor(b, mouseLoc) b.AddCursor(c) b.MergeCursors() return true } func (h *BufPane) skipMultiCursor(forward bool) bool { lastC := h.Buf.GetCursor(h.Buf.NumCursors() - 1) if !lastC.HasSelection() { return false } sel := lastC.GetSelection() searchStart := lastC.CurSelection[1] if !forward { searchStart = lastC.CurSelection[0] } search := string(sel) search = regexp.QuoteMeta(search) if h.multiWord { search = "\\b" + search + "\\b" } match, found, err := h.Buf.FindNext(search, h.Buf.Start(), h.Buf.End(), searchStart, forward, true) if err != nil { InfoBar.Error(err) } if found { lastC.SetSelectionStart(match[0]) lastC.SetSelectionEnd(match[1]) lastC.OrigSelection[0] = lastC.CurSelection[0] lastC.OrigSelection[1] = lastC.CurSelection[1] lastC.Loc = lastC.CurSelection[1] h.Buf.MergeCursors() h.Buf.SetCurCursor(h.Buf.NumCursors() - 1) } else { InfoBar.Message("No matches found") } h.Relocate() return true } // SkipMultiCursor moves the current multiple cursor to the next available position func (h *BufPane) SkipMultiCursor() bool { return h.skipMultiCursor(true) } // SkipMultiCursorBack moves the current multiple cursor to the previous available position func (h *BufPane) SkipMultiCursorBack() bool { return h.skipMultiCursor(false) } // RemoveMultiCursor removes the latest multiple cursor func (h *BufPane) RemoveMultiCursor() bool { if h.Buf.NumCursors() > 1 { h.Buf.RemoveCursor(h.Buf.NumCursors() - 1) h.Buf.SetCurCursor(h.Buf.NumCursors() - 1) h.Buf.UpdateCursors() } else if h.multiWord { h.multiWord = false h.Cursor.Deselect(true) } else { return false } h.Relocate() return true } // RemoveAllMultiCursors removes all cursors except the base cursor func (h *BufPane) RemoveAllMultiCursors() bool { if h.Buf.NumCursors() > 1 || h.multiWord { h.Buf.ClearCursors() h.multiWord = false } else { return false } h.Relocate() return true } // None is an action that does nothing func (h *BufPane) None() bool { return true } zyedidia-micro-6a62575/go.sum0000664000175000017510000001525415125206537015405 0ustar nileshnileshgithub.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/layeh/gopher-luar v1.0.11 h1:ss6t9OtykOiETBScJylSMPhuYAtOmpH5rSX10/wCcis= github.com/layeh/gopher-luar v1.0.11/go.mod h1:TPnIVCZ2RJBndm7ohXyaqfhzjlZ+OA2SZR/YwL8tECk= github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/micro-editor/go-shellquote v0.0.0-20250101105543-feb6c39314f5 h1:D7BPnsedXiKo/e8RTFX419/52ICNhU8UKPQGZ/0yiLc= github.com/micro-editor/go-shellquote v0.0.0-20250101105543-feb6c39314f5/go.mod h1:zaPgW/fDiW4MUfEwxpC+GB/bhvX44NJaNHmRAC9auHQ= github.com/micro-editor/json5 v1.0.1-micro h1:5Y4MuzhkmW0sQQNPvrIVevIOKi557qsznwjRr4iq1AI= github.com/micro-editor/json5 v1.0.1-micro/go.mod h1:cmlPHZ1JKOXNse0/3zwwKj/GUpzAVkzx4lZDkpHl4q0= github.com/micro-editor/tcell/v2 v2.0.13 h1:xyuSpBhSBsUH+bs7FER9IV2/TsQpBmCFiNWJVAEdT68= github.com/micro-editor/tcell/v2 v2.0.13/go.mod h1:ixpjICpoGp83FZVoLYFJPBwCAslHeTnvgPdhJVPLyy0= github.com/micro-editor/terminal v0.0.0-20250324214352-e587e959c6b5 h1:czSkYUNmHuWS2lv8VreufENEXZNOCGZcXd744YKf8yM= github.com/micro-editor/terminal v0.0.0-20250324214352-e587e959c6b5/go.mod h1:OszIG7ockt4osicVHq6gI2QmV4PBDK6H5/Bj8GDGv4Q= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/zyedidia/clipper v0.1.1 h1:HBgguFNDq/QmSQKBnhy4sMKzILINr139VEgAhftOUTw= github.com/zyedidia/clipper v0.1.1/go.mod h1:7YApPNiiTZTXdKKZG92G50qj6mnWEX975Sdu65J7YpQ= github.com/zyedidia/glob v0.0.0-20170209203856-dd4023a66dc3 h1:oMHjjTLfGXVuyOQBYj5/td9WC0mw4g1xDBPovIqmHew= github.com/zyedidia/glob v0.0.0-20170209203856-dd4023a66dc3/go.mod h1:YKbIYP//Eln8eDgAJGI3IDvR3s4Tv9Z9TGIOumiyQ5c= github.com/zyedidia/poller v1.0.1 h1:Tt9S3AxAjXwWGNiC2TUdRJkQDZSzCBNVQ4xXiQ7440s= github.com/zyedidia/poller v1.0.1/go.mod h1:vZXJOHGDcuK08GXhF6IAY0ZFd2WcgOR5DOTp84Uk5eE= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= zyedidia-micro-6a62575/go.mod0000664000175000017510000000261515125206537015355 0ustar nileshnileshmodule github.com/zyedidia/micro/v2 require ( github.com/blang/semver v3.5.1+incompatible github.com/dustin/go-humanize v1.0.0 github.com/go-errors/errors v1.0.1 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-runewidth v0.0.16 github.com/micro-editor/json5 v1.0.1-micro github.com/micro-editor/tcell/v2 v2.0.13 github.com/micro-editor/terminal v0.0.0-20250324214352-e587e959c6b5 github.com/mitchellh/go-homedir v1.1.0 github.com/sergi/go-diff v1.1.0 github.com/stretchr/testify v1.4.0 github.com/yuin/gopher-lua v1.1.1 github.com/zyedidia/clipper v0.1.1 github.com/zyedidia/glob v0.0.0-20170209203856-dd4023a66dc3 golang.org/x/text v0.4.0 gopkg.in/yaml.v2 v2.2.8 layeh.com/gopher-luar v1.0.11 ) require ( github.com/creack/pty v1.1.18 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/gdamore/encoding v1.0.0 // indirect github.com/lucasb-eyer/go-colorful v1.0.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/zyedidia/poller v1.0.1 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/term v0.29.0 // indirect ) replace github.com/kballard/go-shellquote => github.com/micro-editor/go-shellquote v0.0.0-20250101105543-feb6c39314f5 replace layeh.com/gopher-luar v1.0.11 => github.com/layeh/gopher-luar v1.0.11 go 1.19 zyedidia-micro-6a62575/data/0000775000175000017510000000000015125206537015154 5ustar nileshnileshzyedidia-micro-6a62575/data/micro.json0000664000175000017510000004134215125206537017164 0ustar nileshnilesh{ "$comment": "https://github.com/zyedidia/micro", "$schema": "http://json-schema.org/draft-07/schema#", "title": "options", "description": "A micro editor config schema", "type": "object", "properties": { "autoindent": { "description": "Whether to use the same indentation as a previous line\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "autosave": { "description": "A delay between automatic saves\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "integer", "minimum": 0, "default": 0 }, "autosu": { "description": "Whether attempt to use super user privileges\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "backup": { "description": "Whether to backup all open buffers\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "backupdir": { "description": "A directory to store backups\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "default": "" }, "basename": { "description": "Whether to show a basename instead of a full path\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "clipboard": { "description": "A way to access the system clipboard\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "enum": [ "external", "terminal", "internal" ], "default": "external" }, "colorcolumn": { "description": "A position to display a column\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "integer", "minimum": 0, "default": 0 }, "colorscheme": { "description": "A color scheme\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "enum": [ "atom-dark", "bubblegum", "cmc-16", "cmc-tc", "darcula", "default", "dracula-tc", "dukedark-tc", "dukelight-tc", "dukeubuntu-tc", "geany", "gotham", "gruvbox", "gruvbox-tc", "material-tc", "monokai-dark", "monokai", "one-dark", "railscast", "simple", "solarized", "solarized-tc", "sunny-day", "twilight", "zenburn" ], "default": "default" }, "cursorline": { "description": "Whether to highlight a line with a cursor with a different color\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "diffgutter": { "description": "Whether to display diff inticators before lines\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "divchars": { "description": "Divider chars for vertical and horizontal splits\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "default": "|-" }, "divreverse": { "description": "Whether to use inversed color scheme colors for splits\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "encoding": { "description": "An encoding used to open and save files\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "default": "utf-8" }, "eofnewline": { "description": "Whether to add a missing trailing new line\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "fastdirty": { "description": "Whether to use a fast algorithm to determine whether a file is changed\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "fileformat": { "description": "A line ending format\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "enum": [ "unix", "dos" ], "default": "unix" }, "filetype": { "description": "A filetype for the current buffer\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "default": "unknown" }, "hlsearch": { "description": "Whether to highlight all instances of a searched text after a successful search\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "incsearch": { "description": "Whether to enable an incremental search in `Find` prompt\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "ignorecase": { "description": "Whether to perform case-insensitive searches\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "indentchar": { "description": "An indentation character\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "maxLength": 1, "default": " " }, "infobar": { "description": "Whether to enable a line at the bottom where messages are printed\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "keepautoindent": { "description": "Whether add a whitespace while using autoindent\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "keymenu": { "description": "Whether to display nano-style key menu at the bottom\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "matchbrace": { "description": "Whether to show matching braces\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "matchbracestyle": { "description": "Whether to underline or highlight matching braces\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "enum": [ "underline", "highlight" ], "default": "underline" }, "mkparents": { "description": "Whether to create missing directories\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "mouse": { "description": "Whether to enable mouse support\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "paste": { "description": "Whether to treat characters sent from the terminal in a single chunk as a paste event\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "parsecursor": { "description": "Whether to extract a line number and a column to open files with from file names\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "permbackup": { "description": "Whether to permanently save backups\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "pluginchannels": { "description": "A file with list of plugin channels\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "default": "https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json" }, "pluginrepos": { "description": "Plugin repositories\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "array", "uniqueItems": true, "items": { "description": "A pluging repository\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string" }, "default": [] }, "readonly": { "description": "Whether to forbid buffer editing\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "rmtrailingws": { "description": "Whether to remove trailing whitespaces\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "ruler": { "description": "Whether to display line numbers\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "relativeruler": { "description": "Whether to display relative line numbers\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "savecursor": { "description": "Whether to save cursor position in files\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "savehistory": { "description": "Whether to save command history between closing and re-opening editor\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "saveundo": { "description": "Whether to save undo after closing file\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "scrollbar": { "description": "Whether to save undo after closing file\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "scrollmargin": { "description": "A margin at which a view starts scrolling when a cursor approaches an edge of a view\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "integer", "default": 3 }, "scrollspeed": { "description": "Line count to scroll for one scroll event\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "integer", "default": 2 }, "smartpaste": { "description": "Whether to add a leading whitespace while pasting multiple lines\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "softwrap": { "description": "Whether to wrap long lines\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "splitbottom": { "description": "Whether to create a new horizontal split below the current one\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "splitright": { "description": "Whether to create a new vertical split right of the current one\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "statusformatl": { "description": "Format string of left-justified part of the statusline\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "default": "$(filename) $(modified)($(line),$(col)) $(status.paste)| ft:$(opt:filetype) | $(opt:fileformat) | $(opt:encoding)" }, "statusformatr": { "description": "Format string of right-justified part of the statusline\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "default": "$(bind:ToggleKeyMenu): bindings, $(bind:ToggleHelp): help" }, "statusline": { "description": "Whether to display a status line\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "sucmd": { "description": "A super user command\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "string", "default": "sudo", "examples": [ "sudo", "doas" ] }, "syntax": { "description": "Whether to enable a syntax highlighting\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "tabmovement": { "description": "Whether to navigate spaces at the beginning of lines as if they are tabs\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "tabhighlight": { "description": "Whether to invert tab character colors\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "tabreverse": { "description": "Whether to reverse tab bar colors\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "tabsize": { "description": "A tab size\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "integer", "default": 4 }, "tabstospaces": { "description": "Whether to use spaces instead of tabs\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "useprimary": { "description": "Whether to use primary clipboard to copy selections in the background\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": true }, "wordwrap": { "description": "Whether to wrap long lines by words\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false }, "xterm": { "description": "Whether to assume that the current terminal is `xterm`\nhttps://github.com/zyedidia/micro/blob/master/runtime/help/options.md#options", "type": "boolean", "default": false } }, "additionalProperties": false } zyedidia-micro-6a62575/data/io.github.zyedidia.micro.metainfo.xml0000664000175000017510000000426215125206537024304 0ustar nileshnilesh io.github.zyedidia.micro micro.desktop Micro Text Editor A modern and intuitive terminal-based text editor

micro is a terminal-based text editor that aims to be easy to use and intuitive, while also taking advantage of the capabilities of modern terminals. It comes as a single, batteries-included, static binary with no dependencies; you can download and use it right now!

As its name indicates, micro aims to be somewhat of a successor to the nano editor by being easy to install and use. It strives to be enjoyable as a full-time editor for people who prefer to work in a terminal, or those who regularly edit files over SSH.

MIT MIT Development TextEditor micro com.github.zyedidia.micro Zachary Yedidia Micro Text Editor editing its source code https://raw.githubusercontent.com/zyedidia/micro/master/assets/micro-solarized.png https://micro-editor.github.io https://github.com/zyedidia/micro/issues https://micro-editor.github.io/about.html https://micro-editor.github.io/about.html https://github.com/zyedidia https://github.com/zyedidia/micro https://github.com/zyedidia/micro#contributing
zyedidia-micro-6a62575/cmd/0000775000175000017510000000000015125206537015006 5ustar nileshnileshzyedidia-micro-6a62575/cmd/micro/0000775000175000017510000000000015125206537016117 5ustar nileshnileshzyedidia-micro-6a62575/cmd/micro/micro_test.go0000664000175000017510000001553015125206537020622 0ustar nileshnileshpackage main import ( "fmt" "log" "os" "testing" "github.com/go-errors/errors" "github.com/micro-editor/tcell/v2" "github.com/stretchr/testify/assert" "github.com/zyedidia/micro/v2/internal/action" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" ) var tempDir string var sim tcell.SimulationScreen func init() { screen.Events = make(chan tcell.Event, 8) } func startup(args []string) (tcell.SimulationScreen, error) { var err error tempDir, err = os.MkdirTemp("", "micro_test") if err != nil { return nil, err } err = config.InitConfigDir(tempDir) if err != nil { return nil, err } config.InitRuntimeFiles(true) config.InitPlugins() err = config.ReadSettings() if err != nil { return nil, err } err = config.InitGlobalSettings() if err != nil { return nil, err } s, err := screen.InitSimScreen() if err != nil { return nil, err } defer func() { if err := recover(); err != nil { screen.Screen.Fini() fmt.Println("Micro encountered an error:", err) // immediately backup all buffers with unsaved changes for _, b := range buffer.OpenBuffers { if b.Modified() { b.Backup() } } // Print the stack trace too log.Fatalf(errors.Wrap(err, 2).ErrorStack()) } }() err = config.LoadAllPlugins() if err != nil { screen.TermMessage(err) } action.InitBindings() action.InitCommands() err = config.InitColorscheme() if err != nil { return nil, err } b := LoadInput(args) if len(b) == 0 { return nil, errors.New("No buffers opened") } action.InitTabs(b) action.InitGlobals() err = config.RunPluginFn("init") if err != nil { return nil, err } s.InjectResize() handleEvent() return s, nil } func cleanup() { os.RemoveAll(tempDir) } func handleEvent() { screen.Lock() e := screen.Screen.PollEvent() screen.Unlock() if e != nil { screen.Events <- e } for len(screen.DrawChan()) > 0 || len(screen.Events) > 0 { DoEvent() } } func injectKey(key tcell.Key, r rune, mod tcell.ModMask) { sim.InjectKey(key, r, mod) handleEvent() } func injectMouse(x, y int, buttons tcell.ButtonMask, mod tcell.ModMask) { sim.InjectMouse(x, y, buttons, mod) handleEvent() } func injectString(str string) { // the tcell simulation screen event channel can only handle // 10 events at once, so we need to divide up the key events // into chunks of 10 and handle the 10 events before sending // another chunk of events iters := len(str) / 10 extra := len(str) % 10 for i := 0; i < iters; i++ { s := i * 10 e := i*10 + 10 sim.InjectKeyBytes([]byte(str[s:e])) for i := 0; i < 10; i++ { handleEvent() } } sim.InjectKeyBytes([]byte(str[len(str)-extra:])) for i := 0; i < extra; i++ { handleEvent() } } func openFile(file string) { injectKey(tcell.KeyCtrlE, rune(tcell.KeyCtrlE), tcell.ModCtrl) injectString(fmt.Sprintf("open %s", file)) injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone) } func findBuffer(file string) *buffer.Buffer { var buf *buffer.Buffer for _, b := range buffer.OpenBuffers { if b.Path == file { buf = b } } return buf } func createTestFile(t *testing.T, content string) string { f, err := os.CreateTemp(t.TempDir(), "") if err != nil { t.Fatal(err) } defer func() { if err := f.Close(); err != nil { t.Fatal(err) } }() if _, err := f.WriteString(content); err != nil { t.Fatal(err) } return f.Name() } func TestMain(m *testing.M) { var err error sim, err = startup([]string{}) if err != nil { log.Fatalln(err) } retval := m.Run() cleanup() os.Exit(retval) } func TestSimpleEdit(t *testing.T) { file := createTestFile(t, "base content") openFile(file) if findBuffer(file) == nil { t.Fatalf("Could not find buffer %s", file) } injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone) injectKey(tcell.KeyUp, 0, tcell.ModNone) injectString("first line") // test both kinds of backspace for i := 0; i < len("ne"); i++ { injectKey(tcell.KeyBackspace, rune(tcell.KeyBackspace), tcell.ModNone) } for i := 0; i < len(" li"); i++ { injectKey(tcell.KeyBackspace2, rune(tcell.KeyBackspace2), tcell.ModNone) } injectString("foobar") injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl) data, err := os.ReadFile(file) if err != nil { t.Fatal(err) } assert.Equal(t, "firstfoobar\nbase content\n", string(data)) } func TestMouse(t *testing.T) { file := createTestFile(t, "base content") openFile(file) if findBuffer(file) == nil { t.Fatalf("Could not find buffer %s", file) } // buffer: // base content // the selections need to happen at different locations to avoid a double click injectMouse(3, 0, tcell.Button1, tcell.ModNone) injectKey(tcell.KeyLeft, 0, tcell.ModNone) injectMouse(0, 0, tcell.ButtonNone, tcell.ModNone) injectString("secondline") // buffer: // secondlinebase content injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone) // buffer: // secondline // base content injectMouse(2, 0, tcell.Button1, tcell.ModNone) injectMouse(0, 0, tcell.ButtonNone, tcell.ModNone) injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone) // buffer: // // secondline // base content injectKey(tcell.KeyUp, 0, tcell.ModNone) injectString("firstline") // buffer: // firstline // secondline // base content injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl) data, err := os.ReadFile(file) if err != nil { t.Fatal(err) } assert.Equal(t, "firstline\nsecondline\nbase content\n", string(data)) } var srTestStart = `foo foo foofoofoo ErnleÈe foo æðelen ` var srTest2 = `test_string test_string test_stringtest_stringtest_string ErnleÈe test_string æðelen ` var srTest3 = `test_foo test_string test_footest_stringtest_foo ErnleÈe test_string æðelen ` func TestSearchAndReplace(t *testing.T) { file := createTestFile(t, srTestStart) openFile(file) if findBuffer(file) == nil { t.Fatalf("Could not find buffer %s", file) } injectKey(tcell.KeyCtrlE, rune(tcell.KeyCtrlE), tcell.ModCtrl) injectString(fmt.Sprintf("replaceall %s %s", "foo", "test_string")) injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone) injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl) data, err := os.ReadFile(file) if err != nil { t.Fatal(err) } assert.Equal(t, srTest2, string(data)) injectKey(tcell.KeyCtrlE, rune(tcell.KeyCtrlE), tcell.ModCtrl) injectString(fmt.Sprintf("replace %s %s", "string", "foo")) injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone) injectString("ynyny") injectKey(tcell.KeyEscape, 0, tcell.ModNone) injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl) data, err = os.ReadFile(file) if err != nil { t.Fatal(err) } assert.Equal(t, srTest3, string(data)) } func TestMultiCursor(t *testing.T) { // TODO } func TestSettingsPersistence(t *testing.T) { // TODO } // more tests (rendering, tabs, plugins)? zyedidia-micro-6a62575/cmd/micro/micro.go0000664000175000017510000003323115125206537017561 0ustar nileshnileshpackage main import ( "flag" "fmt" "io" "log" "os" "os/signal" "path/filepath" "regexp" "runtime" "runtime/pprof" "sort" "strconv" "syscall" "time" "github.com/go-errors/errors" isatty "github.com/mattn/go-isatty" "github.com/micro-editor/tcell/v2" lua "github.com/yuin/gopher-lua" "github.com/zyedidia/micro/v2/internal/action" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/clipboard" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/shell" "github.com/zyedidia/micro/v2/internal/util" ) var ( // Command line flags flagVersion = flag.Bool("version", false, "Show the version number and information") flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory") flagOptions = flag.Bool("options", false, "Show all option help") flagDebug = flag.Bool("debug", false, "Enable debug mode (prints debug info to ./log.txt)") flagProfile = flag.Bool("profile", false, "Enable CPU profiling (writes profile info to ./micro.prof)") flagPlugin = flag.String("plugin", "", "Plugin command") flagClean = flag.Bool("clean", false, "Clean configuration directory") optionFlags map[string]*string sighup chan os.Signal timerChan chan func() ) func InitFlags() { // Note: keep this in sync with the man page in assets/packaging/micro.1 flag.Usage = func() { fmt.Println("Usage: micro [OPTION]... [FILE]... [+LINE[:COL]] [+/REGEX]") fmt.Println(" micro [OPTION]... [FILE[:LINE[:COL]]]... (only if the `parsecursor` option is enabled)") fmt.Println("-clean") fmt.Println(" \tClean the configuration directory and exit") fmt.Println("-config-dir dir") fmt.Println(" \tSpecify a custom location for the configuration directory") fmt.Println("FILE:LINE[:COL] (only if the `parsecursor` option is enabled)") fmt.Println("FILE +LINE[:COL]") fmt.Println(" \tSpecify a line and column to start the cursor at when opening a buffer") fmt.Println("+/REGEX") fmt.Println(" \tSpecify a regex to search for when opening a buffer") fmt.Println("-options") fmt.Println(" \tShow all options help and exit") fmt.Println("-debug") fmt.Println(" \tEnable debug mode (enables logging to ./log.txt)") fmt.Println("-profile") fmt.Println(" \tEnable CPU profiling (writes profile info to ./micro.prof") fmt.Println(" \tso it can be analyzed later with \"go tool pprof micro.prof\")") fmt.Println("-version") fmt.Println(" \tShow the version number and information and exit") fmt.Print("\nMicro's plugins can be managed at the command line with the following commands.\n") fmt.Println("-plugin install [PLUGIN]...") fmt.Println(" \tInstall plugin(s)") fmt.Println("-plugin remove [PLUGIN]...") fmt.Println(" \tRemove plugin(s)") fmt.Println("-plugin update [PLUGIN]...") fmt.Println(" \tUpdate plugin(s) (if no argument is given, updates all plugins)") fmt.Println("-plugin search [PLUGIN]...") fmt.Println(" \tSearch for a plugin") fmt.Println("-plugin list") fmt.Println(" \tList installed plugins") fmt.Println("-plugin available") fmt.Println(" \tList available plugins") fmt.Print("\nMicro's options can also be set via command line arguments for quick\nadjustments. For real configuration, please use the settings.json\nfile (see 'help options').\n\n") fmt.Println("-