Compare commits

..

1 Commits

Author SHA1 Message Date
Zachary Yedidia
6f302826c8 Add bracket surround 2017-09-13 10:48:53 -04:00
22 changed files with 155 additions and 226 deletions

View File

@@ -50,7 +50,7 @@ You can also check out the website for Micro at https://micro-editor.github.io.
* Macros
* Common editor things such as undo/redo, line numbers, Unicode support, softwrap...
Although not yet implemented, I hope to add more features such as autocompletion ([#174](https://github.com/zyedidia/micro/issues/174)) or a tree view ([#249](https://github.com/zyedidia/micro/issues/249)) in the future.
Although not yet implemented, I hope to add more features such as autocompletion ([#174](https://github.com/zyedidia/micro/issues/174)), and multiple cursors ([#5](https://github.com/zyedidia/micro/issues/5)) in the future.
# Installation

View File

@@ -78,7 +78,7 @@ func (v *View) MousePress(usePlugin bool, e *tcell.EventMouse) bool {
v.Cursor.ResetSelection()
v.Relocate()
}
if time.Since(v.lastClickTime)/time.Millisecond < doubleClickThreshold && (x == v.lastLoc.X && y == v.lastLoc.Y) {
if time.Since(v.lastClickTime)/time.Millisecond < doubleClickThreshold {
if v.doubleClick {
// Triple click
v.lastClickTime = time.Now()
@@ -119,8 +119,6 @@ func (v *View) MousePress(usePlugin bool, e *tcell.EventMouse) bool {
}
}
v.lastLoc = Loc{x, y}
if usePlugin {
PostActionCall("MousePress", v, e)
}
@@ -1854,6 +1852,68 @@ func (v *View) PreviousSplit(usePlugin bool) bool {
return false
}
func (v *View) WrapBracket(usePlugin bool) bool {
if v.Cursor.HasSelection() {
lockPollEvent = true
event := screen.PollEvent()
lockPollEvent = false
ev, ok := event.(*tcell.EventKey)
if !ok {
return false
}
if !strings.Contains("()[]{}\"'", string(ev.Rune())) {
return false
}
start := v.Cursor.CurSelection[0]
end := v.Cursor.CurSelection[1]
if start.Y != end.Y {
return false
}
close := map[string]string{
")": ")",
"]": "]",
"}": "}",
"(": ")",
"[": "]",
"{": "}",
"\"": "\"",
"'": "'",
}
open := map[string]string{
")": "(",
"]": "[",
"}": "{",
"(": "(",
"[": "[",
"{": "{",
"\"": "\"",
"'": "'",
}
if usePlugin && !PreActionCall("WrapBracket", v) {
return false
}
r := string(ev.Rune())
if start.GreaterThan(end) {
start, end = end, start
v.Buf.Insert(start, open[r])
v.Buf.Insert(end.Move(1, v.Buf), close[r])
v.Cursor.CurSelection[1] = start
} else {
v.Buf.Insert(start, open[r])
v.Buf.Insert(end.Move(1, v.Buf), close[r])
v.Cursor.CurSelection[0] = start
}
if usePlugin {
return PostActionCall("WrapBracket", v)
}
}
return false
}
var curMacro []interface{}
var recordingMacro bool

View File

@@ -4,6 +4,8 @@ import (
"io/ioutil"
"os"
"strings"
"github.com/mitchellh/go-homedir"
)
var pluginCompletions []func(string) []string
@@ -20,9 +22,13 @@ func FileComplete(input string) (string, []string) {
var files []os.FileInfo
var err error
if len(dirs) > 1 {
home, _ := homedir.Dir()
directories := strings.Join(dirs[:len(dirs)-1], sep) + sep
directories = ReplaceHome(directories)
if strings.HasPrefix(directories, "~") {
directories = strings.Replace(directories, "~", home, 1)
}
files, err = ioutil.ReadDir(directories)
} else {
files, err = ioutil.ReadDir(".")
@@ -142,55 +148,6 @@ func OptionComplete(input string) (string, []string) {
return chosen, suggestions
}
func OptionValueComplete(inputOpt, input string) (string, []string) {
inputOpt = strings.TrimSpace(inputOpt)
var suggestions []string
localSettings := DefaultLocalSettings()
var optionVal interface{}
for k, option := range 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 "fileformat":
if strings.HasPrefix("unix", input) {
suggestions = append(suggestions, "unix")
}
if strings.HasPrefix("dos", input) {
suggestions = append(suggestions, "dos")
}
}
}
var chosen string
if len(suggestions) == 1 {
chosen = suggestions[0]
}
return chosen, suggestions
}
// MakeCompletion registers a function from a plugin for autocomplete commands
func MakeCompletion(function string) Completion {
pluginCompletions = append(pluginCompletions, LuaFunctionComplete(function))

View File

@@ -69,6 +69,7 @@ var bindingActions = map[string]func(*View, bool) bool{
"PastePrimary": (*View).PastePrimary,
"SelectAll": (*View).SelectAll,
"OpenFile": (*View).OpenFile,
"WrapBracket": (*View).WrapBracket,
"Start": (*View).Start,
"End": (*View).End,
"PageUp": (*View).PageUp,
@@ -438,6 +439,7 @@ func DefaultBindings() map[string]string {
"Down": "CursorDown",
"Right": "CursorRight",
"Left": "CursorLeft",
"Alt-j": "WrapBracket",
"ShiftUp": "SelectUp",
"ShiftDown": "SelectDown",
"ShiftLeft": "SelectLeft",

View File

@@ -2,7 +2,6 @@ package main
import (
"bytes"
"crypto/md5"
"encoding/gob"
"io"
"io/ioutil"
@@ -16,6 +15,7 @@ import (
"time"
"unicode/utf8"
"github.com/mitchellh/go-homedir"
"github.com/zyedidia/micro/cmd/micro/highlight"
)
@@ -57,9 +57,6 @@ type Buffer struct {
syntaxDef *highlight.Def
highlighter *highlight.Highlighter
// Hash of the original buffer -- empty if fastdirty is on
origHash [16]byte
// Buffer local settings
Settings map[string]interface{}
}
@@ -177,7 +174,7 @@ func NewBuffer(reader io.Reader, size int64, path string) *Buffer {
}
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
// We should only use last time's eventhandler if the file wasn't by someone else in the meantime
if b.ModTime == buffer.ModTime {
b.EventHandler = buffer.EventHandler
b.EventHandler.buf = b
@@ -187,13 +184,8 @@ func NewBuffer(reader io.Reader, size int64, path string) *Buffer {
file.Close()
}
if !b.Settings["fastdirty"].(bool) {
if size > 50000 {
// If the file is larger than a megabyte fastdirty needs to be on
b.Settings["fastdirty"] = true
} else {
b.origHash = md5.Sum([]byte(b.String()))
}
if b.Settings["mouse"].(bool) {
screen.EnableMouse()
}
b.cursors = []*Cursor{&b.Cursor}
@@ -389,6 +381,7 @@ func (b *Buffer) Serialize() error {
// SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
func (b *Buffer) SaveAs(filename string) error {
b.UpdateRules()
dir, _ := homedir.Dir()
if b.Settings["rmtrailingws"].(bool) {
r, _ := regexp.Compile(`[ \t]+$`)
for lineNum, line := range b.Lines(0, b.NumLines) {
@@ -409,9 +402,9 @@ func (b *Buffer) SaveAs(filename string) error {
}
str := b.SaveString(b.Settings["fileformat"] == "dos")
data := []byte(str)
err := ioutil.WriteFile(ReplaceHome(filename), data, 0644)
err := ioutil.WriteFile(filename, data, 0644)
if err == nil {
b.Path = filename
b.Path = strings.Replace(filename, "~", dir, 1)
b.IsModified = false
b.ModTime, _ = GetModTime(filename)
return b.Serialize()
@@ -458,13 +451,6 @@ func (b *Buffer) SaveAsWithSudo(filename string) error {
return err
}
func (b *Buffer) Modified() bool {
if b.Settings["fastdirty"].(bool) {
return b.IsModified
}
return b.origHash != md5.Sum([]byte(b.String()))
}
func (b *Buffer) insert(pos Loc, value []byte) {
b.IsModified = true
b.LineArray.insert(pos, value)

View File

@@ -14,6 +14,7 @@ import (
"strings"
humanize "github.com/dustin/go-humanize"
"github.com/mitchellh/go-homedir"
)
// A Command contains a action (a function to call) as well as information about how to autocomplete the command
@@ -89,7 +90,7 @@ func MakeCommand(name, function string, completions ...Completion) {
// DefaultCommands returns a map containing micro's default commands
func DefaultCommands() map[string]StrCommand {
return map[string]StrCommand{
"set": {"Set", []Completion{OptionCompletion, OptionValueCompletion}},
"set": {"Set", []Completion{OptionCompletion, NoCompletion}},
"setlocal": {"SetLocal", []Completion{OptionCompletion, NoCompletion}},
"show": {"Show", []Completion{OptionCompletion, NoCompletion}},
"bind": {"Bind", []Completion{NoCompletion}},
@@ -229,7 +230,8 @@ func TabSwitch(args []string) {
// Cd changes the current working directory
func Cd(args []string) {
if len(args) > 0 {
path := ReplaceHome(args[0])
home, _ := homedir.Dir()
path := strings.Replace(args[0], "~", home, 1)
os.Chdir(path)
for _, tab := range tabs {
for _, view := range tab.views {
@@ -323,7 +325,8 @@ func VSplit(args []string) {
CurView().VSplit(NewBufferFromString("", ""))
} else {
filename := args[0]
filename = ReplaceHome(filename)
home, _ := homedir.Dir()
filename = strings.Replace(filename, "~", home, 1)
file, err := os.Open(filename)
fileInfo, _ := os.Stat(filename)
@@ -352,7 +355,8 @@ func HSplit(args []string) {
CurView().HSplit(NewBufferFromString("", ""))
} else {
filename := args[0]
filename = ReplaceHome(filename)
home, _ := homedir.Dir()
filename = strings.Replace(filename, "~", home, 1)
file, err := os.Open(filename)
fileInfo, _ := os.Stat(filename)
@@ -392,7 +396,8 @@ func NewTab(args []string) {
CurView().AddTab(true)
} else {
filename := args[0]
filename = ReplaceHome(filename)
home, _ := homedir.Dir()
filename = strings.Replace(filename, "~", home, 1)
file, err := os.Open(filename)
fileInfo, _ := os.Stat(filename)

View File

@@ -258,7 +258,7 @@ func (c *Cursor) UpN(amount int) {
runes := []rune(c.buf.Line(c.Y))
c.X = c.GetCharPosInLine(proposedY, c.LastVisualX)
if c.X > len(runes) || (amount < 0 && proposedY == c.Y) {
if c.X > len(runes) {
c.X = len(runes)
}

View File

@@ -231,7 +231,6 @@ const (
OptionCompletion
PluginCmdCompletion
PluginNameCompletion
OptionValueCompletion
)
// Prompt sends the user a message and waits for a response to be typed in
@@ -297,10 +296,6 @@ func (m *Messenger) Prompt(prompt, placeholder, historyType string, completionTy
chosen, suggestions = HelpComplete(currentArg)
} else if completionType == OptionCompletion {
chosen, suggestions = OptionComplete(currentArg)
} else if completionType == OptionValueCompletion {
if currentArgNum-1 > 0 {
chosen, suggestions = OptionValueComplete(args[currentArgNum-1], currentArg)
}
} else if completionType == PluginCmdCompletion {
chosen, suggestions = PluginCmdComplete(currentArg)
} else if completionType == PluginNameCompletion {

View File

@@ -59,6 +59,9 @@ var (
// Event channel
events chan tcell.Event
autosave chan bool
// Read events on another thread or wait for a temporary read
lockPollEvent bool
)
// LoadInput determines which files should be loaded into buffers
@@ -202,10 +205,6 @@ func InitScreen() {
os.Setenv("TERM", oldTerm)
}
if GetGlobalOption("mouse").(bool) {
screen.EnableMouse()
}
screen.SetStyle(defStyle)
}
@@ -254,31 +253,23 @@ func LoadAll() {
var flagVersion = flag.Bool("version", false, "Show the version number and information")
var flagStartPos = flag.String("startpos", "", "LINE,COL to start the cursor at when opening a buffer.")
var flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
var flagOptions = flag.Bool("options", false, "Show all option help")
var optionFlagSet = flag.NewFlagSet("option", flag.ExitOnError)
func main() {
flag.Usage = func() {
fmt.Println("Usage: micro [OPTIONS] [FILE]...")
fmt.Println("-config-dir dir")
fmt.Println(" \tSpecify a custom location for the configuration directory")
fmt.Println("-startpos LINE,COL")
fmt.Println(" \tSpecify a line and column to start the cursor at when opening a buffer")
fmt.Println("-options")
fmt.Println(" \tShow all option help")
fmt.Println("-version")
fmt.Println(" \tShow the version number and information")
fmt.Print("\nMicro's options can also be set via command line arguments for quick\nadjustments. For real configuration, please use the bindings.json\nfile (see 'help options').\n\n")
fmt.Println("-option value")
fmt.Println(" \tSet `option` to `value` for this session")
fmt.Println(" \tFor example: `micro -syntax off file.c`")
fmt.Println("\nUse `micro -options` to see the full list of configuration options")
flag.CommandLine.SetOutput(os.Stdout)
flag.PrintDefaults()
optionFlagSet.SetOutput(os.Stdout)
fmt.Print("\n------------------------------------------------------------------\n")
fmt.Print("Micro's options can also be set via command line arguments for quick\nadjustments. For real configuration, please use the bindings.json\nfile (see 'help options').\n\n")
optionFlagSet.PrintDefaults()
}
optionFlags := make(map[string]*string)
for k, v := range DefaultGlobalSettings() {
optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'", k, v))
optionFlags[k] = optionFlagSet.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'", k, v))
}
flag.Parse()
@@ -291,15 +282,6 @@ func main() {
os.Exit(0)
}
if *flagOptions {
// If -options was passed
for k, v := range DefaultGlobalSettings() {
fmt.Printf("-%s value\n", k)
fmt.Printf(" \tThe %s option. Default value: '%v'\n", k, v)
}
os.Exit(0)
}
// Start the Lua VM for running plugins
L = lua.NewState()
defer L.Close()
@@ -440,8 +422,9 @@ func main() {
// Here is the event loop which runs in a separate thread
go func() {
for {
if screen != nil {
if screen != nil && !lockPollEvent {
events <- screen.PollEvent()
time.Sleep(1 * time.Millisecond)
}
}
}()

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,6 @@
package main
import (
"crypto/md5"
"encoding/json"
"errors"
"io/ioutil"
@@ -199,13 +198,10 @@ func DefaultGlobalSettings() map[string]interface{} {
"colorscheme": "default",
"cursorline": true,
"eofnewline": false,
"fastdirty": true,
"fileformat": "unix",
"rmtrailingws": false,
"ignorecase": false,
"indentchar": " ",
"infobar": true,
"mouse": true,
"rmtrailingws": false,
"ruler": true,
"savecursor": false,
"saveundo": false,
@@ -225,6 +221,8 @@ func DefaultGlobalSettings() map[string]interface{} {
},
"pluginrepos": []string{},
"useprimary": true,
"fileformat": "unix",
"mouse": true,
}
}
@@ -238,12 +236,10 @@ func DefaultLocalSettings() map[string]interface{} {
"colorcolumn": float64(0),
"cursorline": true,
"eofnewline": false,
"fastdirty": true,
"fileformat": "unix",
"rmtrailingws": false,
"filetype": "Unknown",
"ignorecase": false,
"indentchar": " ",
"rmtrailingws": false,
"ruler": true,
"savecursor": false,
"saveundo": false,
@@ -258,6 +254,8 @@ func DefaultLocalSettings() map[string]interface{} {
"tabsize": float64(4),
"tabstospaces": false,
"useprimary": true,
"fileformat": "unix",
"mouse": true,
}
}
@@ -317,14 +315,6 @@ func SetOption(option, value string) error {
}
}
if option == "mouse" {
if !nativeValue.(bool) {
screen.DisableMouse()
} else {
screen.EnableMouse()
}
}
if _, ok := CurView().Buf.Settings[option]; ok {
for _, tab := range tabs {
for _, view := range tab.views {
@@ -368,26 +358,6 @@ func SetLocalOption(option, value string, view *View) error {
return err
}
if option == "fastdirty" {
// If it is being turned off, we have to hash every open buffer
var empty [16]byte
for _, tab := range tabs {
for _, v := range tab.views {
if !nativeValue.(bool) {
if v.Buf.origHash == empty {
data, err := ioutil.ReadFile(v.Buf.AbsPath)
if err != nil {
data = []byte{}
}
v.Buf.origHash = md5.Sum(data)
}
} else {
v.Buf.IsModified = v.Buf.Modified()
}
}
}
}
buf.Settings[option] = nativeValue
if option == "statusline" {
@@ -412,6 +382,14 @@ func SetLocalOption(option, value string, view *View) error {
}
}
if option == "mouse" {
if !nativeValue.(bool) {
screen.DisableMouse()
} else {
screen.EnableMouse()
}
}
return nil
}

View File

@@ -20,7 +20,7 @@ func (sline *Statusline) Display() {
file := sline.view.Buf.GetName()
// If the buffer is dirty (has been modified) write a little '+'
if sline.view.Buf.Modified() {
if sline.view.Buf.IsModified {
file += " +"
}

View File

@@ -91,7 +91,7 @@ func TabbarString() (string, map[int]int) {
}
buf := t.views[t.CurView].Buf
str += buf.GetName()
if buf.Modified() {
if buf.IsModified {
str += " +"
}
if i == curTab {

View File

@@ -12,7 +12,6 @@ import (
"unicode/utf8"
"github.com/mattn/go-runewidth"
homedir "github.com/mitchellh/go-homedir"
)
// Util.go is a collection of utility functions that are used throughout
@@ -364,18 +363,3 @@ func JoinCommandArgs(args ...string) string {
return buf.String()
}
// 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 {
if !strings.HasPrefix(path, "~") {
return path
}
home, err := homedir.Dir()
if err != nil {
messenger.Error("Could not find home directory: ", err)
return path
}
return strings.Replace(path, "~", home, 1)
}

View File

@@ -6,6 +6,7 @@ import (
"strings"
"time"
"github.com/mitchellh/go-homedir"
"github.com/zyedidia/tcell"
)
@@ -72,7 +73,6 @@ type View struct {
// This stores when the last click was
// This is useful for detecting double and triple clicks
lastClickTime time.Time
lastLoc Loc
// lastCutTime stores when the last ctrl+k was issued.
// It is used for clearing the clipboard to replace it with fresh cut lines.
@@ -198,7 +198,7 @@ func (v *View) ScrollDown(n int) {
// If there are unsaved changes, the user will be asked if the view can be closed
// causing them to lose the unsaved changes
func (v *View) CanClose() bool {
if v.Type == vtDefault && v.Buf.Modified() {
if v.Type == vtDefault && v.Buf.IsModified {
var choice bool
var canceled bool
if v.Buf.Settings["autosave"].(bool) {
@@ -243,7 +243,8 @@ func (v *View) OpenBuffer(buf *Buffer) {
// Open opens the given file in the view
func (v *View) Open(filename string) {
filename = ReplaceHome(filename)
home, _ := homedir.Dir()
filename = strings.Replace(filename, "~", home, 1)
file, err := os.Open(filename)
fileInfo, _ := os.Stat(filename)

View File

@@ -161,22 +161,6 @@ Here are the options that you can set:
default value: `on`
* `fileformat`: this determines what kind of line endings micro will use for the file. Unix line endings
are just `\n` (lf) whereas dos line endings are `\r\n` (crlf). The two possible values for this option
are `unix` and `dos`. The fileformat will be automatically detected 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.
default value: `unix`
* `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 is only for people who really care about having accurate
modified status.
default value: `on`
---
Default plugin options:
@@ -195,6 +179,13 @@ Default plugin options:
default value: `on`
* `fileformat`: this determines what kind of line endings micro will use for the file. Unix line endings
are just `\n` (lf) whereas dos line endings are `\r\n` (crlf). The two possible values for this option
are `unix` and `dos`. The fileformat will be automatically detected 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.
default value: `unix`
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

View File

@@ -5,7 +5,7 @@ detect:
rules:
## Keywords
- type.keyword: "(?i)^(FROM|MAINTAINER|RUN|CMD|LABEL|EXPOSE|ENV|ADD|COPY|ENTRYPOINT|VOLUME|USER|WORKDIR|ONBUILD|ARG|HEALTHCHECK|STOPSIGNAL|SHELL)[[:space:]]"
- keyword: "(?i)^(FROM|MAINTAINER|RUN|CMD|LABEL|EXPOSE|ENV|ADD|COPY|ENTRYPOINT|VOLUME|USER|WORKDIR|ONBUILD|ARG|HEALTHCHECK|STOPSIGNAL|SHELL)[[:space:]]"
## Brackets & parenthesis
- statement: "(\\(|\\)|\\[|\\])"

View File

@@ -12,18 +12,17 @@ rules:
end: "$"
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:"
- keyword: "#[[:space:]](deleted|modified|new file|renamed):[[:space:]].*"
- keyword: "#[[:space:]]deleted:"
- keyword: "#[[:space:]]modified:"
- keyword: "#[[:space:]]new file:"
- keyword: "#[[:space:]]renamed:"
# Untracked filenames
- error: "^# [^/?*:;{}\\\\]+\\.[^/?*:;{}\\\\]+$"
- 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"
- keyword: "^#[[:space:]]Changes.*[:]"
- keyword: "^#[[:space:]]Your branch and '[^']+"
- keyword: "^#[[:space:]]Your branch and '"
- keyword: "^#[[:space:]]On branch [^ ]+"
- keyword: "^#[[:space:]]On branch"
# Recolor hash symbols
- special: "#"

View File

@@ -5,7 +5,7 @@ detect:
rules:
- constant: "\\<(true|false)\\>"
- type.keyword: "^[[:space:]]*[^=]*="
- keyword: "^[[:space:]]*[^=]*="
- constant: "^[[:space:]]*\\[.*\\]$"
- constant: "\"(\\\\.|[^\"])*\"|'(\\\\.|[^'])*'"
- comment:

View File

@@ -7,33 +7,21 @@ detect:
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))\\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|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: "(,|\\.)"
- identifier:
start: "[\\$@%]"
end: "\\W"
start: "[$@%]"
end: "((?i) |[^0-9A-Z_]|-)"
rules: []
- constant.string: "\"\\(.*\\)\"|qq?\\|.*\\||qq?\\{.*\\}|qq?\\/.*\\/"
- constant.string: "\".*\"|qq\\|.*\\|"
- default: "[sm]/.*/"
- preproc:
start: "(^use| = new)"
end: ";"
rules: []
- comment:
start: "#"
end: "$"
rules: []
- comment:
start: "^="
end: "^=cut"
rules: []
- comment: "#.*"
- identifier.macro:
start: "<< 'STOP'"
end: "STOP"
rules: []

View File

@@ -9,7 +9,7 @@ rules:
- 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"
- 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"