From 43187c043857b579cfdb53a09d098ecc06fc5505 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Sun, 3 Apr 2016 15:22:31 -0400 Subject: [PATCH 1/3] Add search and replace --- src/buffer.go | 16 ++++++++++++++++ src/command.go | 39 +++++++++++++++++++++++++++++++++++++++ src/eventhandler.go | 6 ++++++ 3 files changed, 61 insertions(+) diff --git a/src/buffer.go b/src/buffer.go index 0ffe5fc8..fa32a631 100644 --- a/src/buffer.go +++ b/src/buffer.go @@ -3,6 +3,7 @@ package main import ( "github.com/vinzmay/go-rope" "io/ioutil" + "regexp" "strings" ) @@ -110,6 +111,21 @@ func (b *Buffer) Remove(start, end int) string { return removed } +func (b *Buffer) Replace(search, replace string) error { + re, err := regexp.Compile(search) + if err != nil { + return err + } + text := re.ReplaceAllString(b.text, replace) + if text == "" { + b.r = new(rope.Rope) + } else { + b.r = rope.New(text) + } + b.Update() + return nil +} + // Len gives the length of the buffer func (b *Buffer) Len() int { return b.r.Len() diff --git a/src/command.go b/src/command.go index cfffc22a..1994e207 100644 --- a/src/command.go +++ b/src/command.go @@ -2,6 +2,7 @@ package main import ( "os" + "regexp" "strings" ) @@ -35,5 +36,43 @@ func HandleCommand(input string, view *View) { } case "save": view.Save() + case "replace": + r := regexp.MustCompile(`"[^"\\]*(?:\\.[^"\\]*)*"|[^\s]*`) + replaceCmd := r.FindAllString(strings.Join(args, " "), -1) + if len(replaceCmd) != 2 { + messenger.Error("Invalid replace statement: " + strings.Join(args, " ")) + return + } + + search := string(replaceCmd[0]) + replace := string(replaceCmd[1]) + + if strings.HasPrefix(search, `"`) && strings.HasSuffix(search, `"`) { + search = search[1 : len(search)-1] + } + if strings.HasPrefix(replace, `"`) && strings.HasSuffix(replace, `"`) { + replace = replace[1 : len(replace)-1] + } + + search = strings.Replace(search, `\"`, `"`, -1) + replace = strings.Replace(replace, `\"`, `"`, -1) + + messenger.Error(search + " -> " + replace) + + regex, err := regexp.Compile(search) + if err != nil { + messenger.Error(err.Error()) + return + } + + for { + match := regex.FindStringIndex(view.buf.text) + if match == nil { + break + } + view.eh.Replace(match[0], match[1], replace) + } + default: + messenger.Error("Unknown command: " + cmd) } } diff --git a/src/eventhandler.go b/src/eventhandler.go index b563151d..c54319eb 100644 --- a/src/eventhandler.go +++ b/src/eventhandler.go @@ -83,6 +83,12 @@ func (eh *EventHandler) Remove(start, end int) { eh.Execute(e) } +// Replace deletes from start to end and replaces it with the given string +func (eh *EventHandler) Replace(start, end int, 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.redo.Len() > 0 { From 0be8e9be444e6131cf5243cbbbb220af9d8cc331 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Sun, 3 Apr 2016 17:48:21 -0400 Subject: [PATCH 2/3] Add flags and yes no prompt --- src/command.go | 23 +++++++++++++++++++++-- src/messenger.go | 23 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/command.go b/src/command.go index 1994e207..7acfcb57 100644 --- a/src/command.go +++ b/src/command.go @@ -39,11 +39,17 @@ func HandleCommand(input string, view *View) { case "replace": r := regexp.MustCompile(`"[^"\\]*(?:\\.[^"\\]*)*"|[^\s]*`) replaceCmd := r.FindAllString(strings.Join(args, " "), -1) - if len(replaceCmd) != 2 { + if len(replaceCmd) < 2 { messenger.Error("Invalid replace statement: " + strings.Join(args, " ")) return } + var flags string + if len(replaceCmd) == 3 { + // The user included some flags + flags = replaceCmd[2] + } + search := string(replaceCmd[0]) replace := string(replaceCmd[1]) @@ -57,7 +63,7 @@ func HandleCommand(input string, view *View) { search = strings.Replace(search, `\"`, `"`, -1) replace = strings.Replace(replace, `\"`, `"`, -1) - messenger.Error(search + " -> " + replace) + // messenger.Error(search + " -> " + replace) regex, err := regexp.Compile(search) if err != nil { @@ -65,13 +71,26 @@ func HandleCommand(input string, view *View) { return } + found := false for { match := regex.FindStringIndex(view.buf.text) if match == nil { break } + found = true + if strings.Contains(flags, "c") { + // // The 'check' flag was used + // if messenger.YesNoPrompt("Perform replacement?") { + // view.eh.Replace(match[0], match[1], replace) + // } else { + // continue + // } + } view.eh.Replace(match[0], match[1], replace) } + if !found { + messenger.Message("Nothing matched " + search) + } default: messenger.Error("Unknown command: " + cmd) } diff --git a/src/messenger.go b/src/messenger.go index ca80b1b4..e7984bf3 100644 --- a/src/messenger.go +++ b/src/messenger.go @@ -71,6 +71,29 @@ func (m *Messenger) Error(msg string) { m.hasMessage = true } +// YesNoPrompt asks the user a yes or no question (waits for y or n) and returns the result +func (m *Messenger) YesNoPrompt(prompt string) bool { + m.Message(prompt) + + for { + m.Clear() + m.Display() + screen.Show() + event := screen.PollEvent() + + switch e := event.(type) { + case *tcell.EventKey: + if e.Key() == tcell.KeyRune { + if e.Rune() == 'y' { + return true + } else if e.Rune() == 'n' { + return false + } + } + } + } +} + // Prompt sends the user a message and waits for a response to be typed in // This function blocks the main loop while waiting for input func (m *Messenger) Prompt(prompt string) (string, bool) { From 22cfb20a3ba66b6ac3a93db4ad2820b96de9394e Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Mon, 4 Apr 2016 15:11:14 -0400 Subject: [PATCH 3/3] Fix 256 color lookup --- src/colorscheme.go | 39 +++++++++++++++++++++++++++++++++------ src/cursor.go | 4 ++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/colorscheme.go b/src/colorscheme.go index 721e243f..6b6e757e 100644 --- a/src/colorscheme.go +++ b/src/colorscheme.go @@ -156,16 +156,43 @@ func StringToColor(str string) tcell.Color { // GetColor256 returns the tcell color for a number between 0 and 255 func GetColor256(color int) tcell.Color { - ansiColors := []tcell.Color{tcell.ColorBlack, tcell.ColorMaroon, tcell.ColorGreen, + colors := []tcell.Color{tcell.ColorBlack, tcell.ColorMaroon, tcell.ColorGreen, tcell.ColorOlive, tcell.ColorNavy, tcell.ColorPurple, tcell.ColorTeal, tcell.ColorSilver, tcell.ColorGray, tcell.ColorRed, tcell.ColorLime, tcell.ColorYellow, tcell.ColorBlue, tcell.ColorFuchsia, tcell.ColorAqua, - tcell.ColorWhite} - - if color >= 0 && color <= 15 { - return ansiColors[color] + tcell.ColorWhite, tcell.Color16, tcell.Color17, tcell.Color18, tcell.Color19, tcell.Color20, + tcell.Color21, tcell.Color22, tcell.Color23, tcell.Color24, tcell.Color25, tcell.Color26, tcell.Color27, tcell.Color28, + tcell.Color29, tcell.Color30, tcell.Color31, tcell.Color32, tcell.Color33, tcell.Color34, tcell.Color35, tcell.Color36, + tcell.Color37, tcell.Color38, tcell.Color39, tcell.Color40, tcell.Color41, tcell.Color42, tcell.Color43, tcell.Color44, + tcell.Color45, tcell.Color46, tcell.Color47, tcell.Color48, tcell.Color49, tcell.Color50, tcell.Color51, tcell.Color52, + tcell.Color53, tcell.Color54, tcell.Color55, tcell.Color56, tcell.Color57, tcell.Color58, tcell.Color59, tcell.Color60, + tcell.Color61, tcell.Color62, tcell.Color63, tcell.Color64, tcell.Color65, tcell.Color66, tcell.Color67, tcell.Color68, + tcell.Color69, tcell.Color70, tcell.Color71, tcell.Color72, tcell.Color73, tcell.Color74, tcell.Color75, tcell.Color76, + tcell.Color77, tcell.Color78, tcell.Color79, tcell.Color80, tcell.Color81, tcell.Color82, tcell.Color83, tcell.Color84, + tcell.Color85, tcell.Color86, tcell.Color87, tcell.Color88, tcell.Color89, tcell.Color90, tcell.Color91, tcell.Color92, + tcell.Color93, tcell.Color94, tcell.Color95, tcell.Color96, tcell.Color97, tcell.Color98, tcell.Color99, tcell.Color100, + tcell.Color101, tcell.Color102, tcell.Color103, tcell.Color104, tcell.Color105, tcell.Color106, tcell.Color107, tcell.Color108, + tcell.Color109, tcell.Color110, tcell.Color111, tcell.Color112, tcell.Color113, tcell.Color114, tcell.Color115, tcell.Color116, + tcell.Color117, tcell.Color118, tcell.Color119, tcell.Color120, tcell.Color121, tcell.Color122, tcell.Color123, tcell.Color124, + tcell.Color125, tcell.Color126, tcell.Color127, tcell.Color128, tcell.Color129, tcell.Color130, tcell.Color131, tcell.Color132, + tcell.Color133, tcell.Color134, tcell.Color135, tcell.Color136, tcell.Color137, tcell.Color138, tcell.Color139, tcell.Color140, + tcell.Color141, tcell.Color142, tcell.Color143, tcell.Color144, tcell.Color145, tcell.Color146, tcell.Color147, tcell.Color148, + tcell.Color149, tcell.Color150, tcell.Color151, tcell.Color152, tcell.Color153, tcell.Color154, tcell.Color155, tcell.Color156, + tcell.Color157, tcell.Color158, tcell.Color159, tcell.Color160, tcell.Color161, tcell.Color162, tcell.Color163, tcell.Color164, + tcell.Color165, tcell.Color166, tcell.Color167, tcell.Color168, tcell.Color169, tcell.Color170, tcell.Color171, tcell.Color172, + tcell.Color173, tcell.Color174, tcell.Color175, tcell.Color176, tcell.Color177, tcell.Color178, tcell.Color179, tcell.Color180, + tcell.Color181, tcell.Color182, tcell.Color183, tcell.Color184, tcell.Color185, tcell.Color186, tcell.Color187, tcell.Color188, + tcell.Color189, tcell.Color190, tcell.Color191, tcell.Color192, tcell.Color193, tcell.Color194, tcell.Color195, tcell.Color196, + tcell.Color197, tcell.Color198, tcell.Color199, tcell.Color200, tcell.Color201, tcell.Color202, tcell.Color203, tcell.Color204, + tcell.Color205, tcell.Color206, tcell.Color207, tcell.Color208, tcell.Color209, tcell.Color210, tcell.Color211, tcell.Color212, + tcell.Color213, tcell.Color214, tcell.Color215, tcell.Color216, tcell.Color217, tcell.Color218, tcell.Color219, tcell.Color220, + tcell.Color221, tcell.Color222, tcell.Color223, tcell.Color224, tcell.Color225, tcell.Color226, tcell.Color227, tcell.Color228, + tcell.Color229, tcell.Color230, tcell.Color231, tcell.Color232, tcell.Color233, tcell.Color234, tcell.Color235, tcell.Color236, + tcell.Color237, tcell.Color238, tcell.Color239, tcell.Color240, tcell.Color241, tcell.Color242, tcell.Color243, tcell.Color244, + tcell.Color245, tcell.Color246, tcell.Color247, tcell.Color248, tcell.Color249, tcell.Color250, tcell.Color251, tcell.Color252, + tcell.Color253, tcell.Color254, tcell.Color255, } - return tcell.GetColor("Color" + strconv.Itoa(color)) + return colors[color] } diff --git a/src/cursor.go b/src/cursor.go index 8b0f56fb..e36fc3ad 100644 --- a/src/cursor.go +++ b/src/cursor.go @@ -126,6 +126,10 @@ func (c *Cursor) AddLineToSelection() { // SelectWord selects the word the cursor is currently on func (c *Cursor) SelectWord() { + if len(c.v.buf.lines[c.y]) == 0 { + return + } + if !IsWordChar(string(c.RuneUnder(c.x))) { loc := c.Loc() c.curSelection[0] = loc