diff --git a/buffer.go b/buffer.go index 3194dcf6..88b88229 100644 --- a/buffer.go +++ b/buffer.go @@ -25,6 +25,11 @@ type Buffer struct { // These variables are updated in the update() function text string lines []string + + // Syntax highlighting rules + rules string + // File type of the buffer + filetype string } // NewBuffer creates a new buffer from `txt` with path and name `path` @@ -35,6 +40,8 @@ func NewBuffer(txt, path string) *Buffer { b.name = path b.savedText = txt + b.rules, b.filetype = GetRules(path) + b.Update() return b diff --git a/highlighter.go b/highlighter.go index 1da383a2..860c6083 100644 --- a/highlighter.go +++ b/highlighter.go @@ -1,36 +1,81 @@ package main import ( + "fmt" "github.com/gdamore/tcell" "io/ioutil" + "os/user" + "path/filepath" "regexp" "strings" ) -var syntaxRules string +var syntaxFiles map[*regexp.Regexp][2]string -func GetRules() string { - file, err := ioutil.ReadFile("syntax.micro") - if err != nil { - return "" - } - return string(file) +func LoadSyntaxFiles() { + usr, _ := user.Current() + dir := usr.HomeDir + LoadSyntaxFilesFromDir(dir + "/.micro") } -// Match ... -func Match(str string) map[int]tcell.Style { - rules := strings.TrimSpace(GetRules()) +func LoadSyntaxFilesFromDir(dir string) { + syntaxFiles = make(map[*regexp.Regexp][2]string) + files, _ := ioutil.ReadDir(dir) + for _, f := range files { + if filepath.Ext(f.Name()) == ".micro" { + text, err := ioutil.ReadFile(dir + "/" + f.Name()) + + if err != nil { + fmt.Println("Error loading syntax files:", err) + continue + } + lines := strings.Split(string(text), "\n") + parser, _ := regexp.Compile(`syntax "(.*?)"\s+"(.*)"`) + matches := parser.FindSubmatch([]byte(lines[0])) + + fileExtRegex, err := regexp.Compile(string(matches[2])) + if err != nil { + // Error with the regex! + continue + } + + syntaxFiles[fileExtRegex] = [2]string{string(text), string(matches[1])} + } + } +} + +// GetRules finds the syntax rules that should be used for the buffer +// and returns them. It also returns the filetype of the file +func GetRules(filename string) (string, string) { + for r := range syntaxFiles { + if r.MatchString(filename) { + return syntaxFiles[r][0], syntaxFiles[r][1] + } + } + return "", "Unknown" +} + +// Match takes a buffer and returns a map specifying how it should be syntax highlighted +// The map is from character numbers to styles, so map[3] represents the style change +// at the third character in the buffer +func Match(rules string, buf *Buffer) map[int]tcell.Style { + // rules := strings.TrimSpace(GetRules(buf)) + str := buf.text lines := strings.Split(rules, "\n") m := make(map[int]tcell.Style) parser, _ := regexp.Compile(`color (.*?)\s+"(.*)"`) for _, line := range lines { + if strings.TrimSpace(line) == "" || strings.TrimSpace(line)[0] == '#' || strings.HasPrefix(line, "syntax") { + // Ignore this line + continue + } submatch := parser.FindSubmatch([]byte(line)) color := string(submatch[1]) regex, err := regexp.Compile(string(submatch[2])) if err != nil { - continue // Error with the regex! + continue } st := StringToStyle(color) diff --git a/micro.go b/micro.go index 32d2d828..0c62f6f0 100644 --- a/micro.go +++ b/micro.go @@ -37,6 +37,8 @@ func main() { input = bytes } + LoadSyntaxFiles() + s, e := tcell.NewScreen() if e != nil { fmt.Fprintf(os.Stderr, "%v\n", e) diff --git a/statusline.go b/statusline.go index 6de3d4c3..8bc95c78 100644 --- a/statusline.go +++ b/statusline.go @@ -23,12 +23,16 @@ func (sl *Statusline) Display() { file += " +" } file += " (" + strconv.Itoa(sl.v.cursor.y+1) + "," + strconv.Itoa(sl.v.cursor.GetVisualX()+1) + ")" + filetype := sl.v.buf.filetype + file += " " + filetype statusLineStyle := tcell.StyleDefault.Reverse(true) for x := 0; x < sl.v.width; x++ { if x < Count(file) { sl.v.s.SetContent(x, y, []rune(file)[x], nil, statusLineStyle) + // } else if x > sl.v.width-Count(filetype)-1 { + // sl.v.s.SetContent(x, y, []rune(filetype)[Count(filetype)-(sl.v.width-1-x)-1], nil, statusLineStyle) } else { sl.v.s.SetContent(x, y, ' ', nil, statusLineStyle) } diff --git a/view.go b/view.go index 657bc4df..55fad68d 100644 --- a/view.go +++ b/view.go @@ -39,6 +39,8 @@ func NewViewWidthHeight(buf *Buffer, s tcell.Screen, w, h int) *View { v.buf = buf v.s = s + v.buf.rules, v.buf.filetype = GetRules(v.buf.path) + v.topline = 0 v.height = h - 1 v.width = w @@ -301,7 +303,7 @@ func (v *View) Display() { charNum := v.cursor.loc + v.cursor.Distance(0, v.topline) - matches := Match(v.buf.text) + matches := Match(v.buf.rules, v.buf) // Convert the length of buffer to a string, and get the length of the string // We are going to have to offset by that amount