// Execute the InitEvent. func (ie *InitEvent) call() { log.Debug("OnInit callbacks executing") defer log.Debug("OnInit callbacks finished") for _, ev := range *ie { ev() } }
func (e *Editor) RunCommand(name string, args Args) { // TODO? var ( wnd *Window v *View ) if wnd = e.ActiveWindow(); wnd != nil { v = wnd.ActiveView() } // TODO: what's the command precedence? if c := e.cmdHandler.TextCommands[name]; c != nil { if err := e.CommandHandler().RunTextCommand(v, name, args); err != nil { log.Debug("Couldn't run textcommand: %s", err) } } else if c := e.cmdHandler.WindowCommands[name]; c != nil { if err := e.CommandHandler().RunWindowCommand(wnd, name, args); err != nil { log.Debug("Couldn't run windowcommand: %s", err) } } else if c := e.cmdHandler.ApplicationCommands[name]; c != nil { if err := e.CommandHandler().RunApplicationCommand(name, args); err != nil { log.Debug("Couldn't run applicationcommand: %s", err) } } else { log.Debug("Couldn't find command to run") } }
func setColorMode() { var ( mode256 bool pal = make([]termbox.RGB, 0, 256) ) if err := termbox.SetColorMode(termbox.ColorMode256); err != nil { log.Error("Unable to use 256 color mode: %s", err) } else { log.Debug("Using 256 color mode") mode256 = true } if !mode256 { pal = pal[:10] // Not correct, but whatever pal[termbox.ColorBlack] = termbox.RGB{0, 0, 0} pal[termbox.ColorWhite] = termbox.RGB{255, 255, 255} pal[termbox.ColorRed] = termbox.RGB{255, 0, 0} pal[termbox.ColorGreen] = termbox.RGB{0, 255, 0} pal[termbox.ColorBlue] = termbox.RGB{0, 0, 255} pal[termbox.ColorMagenta] = termbox.RGB{255, 0, 255} pal[termbox.ColorYellow] = termbox.RGB{255, 255, 0} pal[termbox.ColorCyan] = termbox.RGB{0, 255, 255} diff := func(i, j byte) int { v := int(i) - int(j) if v < 0 { return -v } return v } palLut = func(col textmate.Color) termbox.Attribute { mindist := 10000000 mini := 0 for i, c := range pal { if dist := diff(c.R, col.R) + diff(c.G, col.G) + diff(c.B, col.B); dist < mindist { mindist = dist mini = i } } return termbox.Attribute(mini) } } else { palLut = func(col textmate.Color) termbox.Attribute { tc := termbox.RGB{col.R, col.G, col.B} for i, c := range pal { if c == tc { return termbox.Attribute(i) } } l := len(pal) log.Debug("Adding colour: %d %+v %+v", l, col, tc) pal = append(pal, tc) termbox.SetColorPalette(pal) return termbox.Attribute(l) } } }
func (ch *commandHandler) RunTextCommand(view *View, name string, args Args) error { lvl := log.FINE p := Prof.Enter("tc") defer p.Exit() t := time.Now() if ch.log { lvl = log.DEBUG } log.Logf(lvl, "Running text command: %s %v", name, args) if c, ok := ch.TextCommands[name].(TextCommand); c != nil && ok { if err := ch.init(c, args); err != nil && ch.verbose { log.Debug("Command initialization failed: %s", err) return err } else if err := view.runCommand(c, name); err != nil { log.Logf(lvl, "Command execution failed: %s", err) return err } } else if w := view.Window(); w != nil { if c, ok := ch.WindowCommands[name].(WindowCommand); c != nil && ok { if err := w.runCommand(c, name); err != nil { log.Logf(lvl, "Command execution failed: %s", err) return err } } } log.Logf(lvl, "Ran text command: %s %s", name, time.Since(t)) return nil }
// key HandleFunc for the http /key endpoint. This only happens if the client // doesn't support websockets. func (t *tbfe) key(w http.ResponseWriter, req *http.Request) { log.Debug("key: %s", req) kc := req.FormValue("keyCode") var kp keys.KeyPress v, _ := strconv.ParseInt(kc, 10, 32) if req.FormValue("altKey") == "true" { kp.Alt = true } if req.FormValue("ctrlKey") == "true" { kp.Ctrl = true } if req.FormValue("metaKey") == "true" { kp.Super = true } if req.FormValue("shiftKey") == "true" { kp.Shift = true } if !kp.Shift { v = int64(unicode.ToLower(rune(v))) } kp.Key = keys.Key(v) kp.Text = string(v) backend.GetEditor().HandleInput(kp) }
// TODO func Init() { l := py.NewLock() defer l.Unlock() m, err := py.Import("sublime_plugin") if err != nil { panic(err) } sys, err := py.Import("sys") if err != nil { log.Debug(err) } else { defer sys.Decref() } if watcher, err = watch.NewWatcher(); err != nil { log.Error("Couldn't create watcher: %s", err) } plugins := packages.ScanPlugins(backend.LIME_USER_PACKAGES_PATH, ".py") for _, p := range plugins { // TODO: add all plugins after supporting all commands if p.Name() == path.Join("..", "..", "3rdparty", "bundles", "Vintageous") { pl := newPlugin(p, m) pl.reload() if err := watcher.Watch(pl.Name(), pl); err != nil { log.Error("Couldn't watch %s: %s", pl.Name(), err) } } } go watcher.Observe() }
func sublime_set_timeout(tu *py.Tuple, kwargs *py.Dict) (py.Object, error) { var ( pyarg py.Object ) if tu.Size() != 2 { return nil, fmt.Errorf("Unexpected argument count: %d", tu.Size()) } if i, err := tu.GetItem(0); err != nil { return nil, err } else { pyarg = i } if i, err := tu.GetItem(1); err != nil { return nil, err } else if v, err := fromPython(i); err != nil { return nil, err } else if v2, ok := v.(int); !ok { return nil, fmt.Errorf("Expected int not %s", i.Type()) } else { pyarg.Incref() go func() { time.Sleep(time.Millisecond * time.Duration(v2)) l := py.NewLock() defer l.Unlock() defer pyarg.Decref() if ret, err := pyarg.Base().CallFunctionObjArgs(); err != nil { log.Debug("Error in callback: %v", err) } else { ret.Decref() } }() } return toPython(nil) }
func (w *Watcher) Watch(name string, cb interface{}) error { log.Finest("Watch(%s)", name) fi, err := os.Stat(name) isDir := err == nil && fi.IsDir() // If the file doesn't exist currently we will add watcher for file // directory and look for create event inside the directory if os.IsNotExist(err) { log.Debug("File doesn't exist, Watching parent dir") if err := w.Watch(filepath.Dir(name), nil); err != nil { return err } } w.lock.Lock() defer w.lock.Unlock() if err := w.add(name, cb); err != nil { if !isDir || exist(w.dirs, name) { return err } } // If exists in watchers we are already watching the path // Or // If the file is under one of watched dirs // // no need to create watcher if exist(w.watchers, name) || (!isDir && exist(w.dirs, filepath.Dir(name))) { return nil } if err := w.watch(name); err != nil { return err } if isDir { w.flushDir(name) } return nil }
func main() { flag.Parse() log.AddFilter("file", log.FINEST, log.NewFileLogWriter("debug.log", *rotateLog)) defer func() { py.NewLock() py.Finalize() }() if err := termbox.Init(); err != nil { log.Close(err) return } defer func() { termbox.Close() log.Debug(util.Prof) if err := recover(); err != nil { log.Critical(err) panic(err) } }() t := createFrontend() go t.renderthread() t.loop() }
func (t *tbfe) loop() { timechan := make(chan bool, 0) // Only set up the timers if we should actually blink the cursor // This should somehow be changable on an OnSettingsChanged callback if p := t.editor.Settings().Get("caret_blink", true).(bool); p { duration := time.Second / 2 if p, ok := t.editor.Settings().Get("caret_blink_phase", 1.0).(float64); ok { duration = time.Duration(float64(time.Second)*p) / 2 } timer := time.NewTimer(duration) defer func() { timer.Stop() close(timechan) }() go func() { for _ = range timer.C { timechan <- true timer.Reset(duration) } }() } // Due to termbox still running, we can't close evchan evchan := make(chan termbox.Event, 32) go func() { for { evchan <- termbox.PollEvent() } }() for { p := util.Prof.Enter("mainloop") select { case ev := <-evchan: mp := util.Prof.Enter("evchan") switch ev.Type { case termbox.EventError: log.Debug("error occured") return case termbox.EventResize: t.handleResize(ev.Height, ev.Width, false) case termbox.EventKey: t.handleInput(ev) blink = false } mp.Exit() case <-timechan: blink = !blink t.render() case <-t.shutdown: return } p.Exit() } }
func onInit() { l := py.NewLock() defer l.Unlock() m, err := py.Import("sublime_plugin") if err != nil { panic(err) } sys, err := py.Import("sys") if err != nil { log.Debug(err) } else { defer sys.Decref() } if watcher, err = watch.NewWatcher(); err != nil { log.Errorf("Couldn't create watcher: %s", err) } // TODO: add all plugins after supporting all commands // plugins := packages.ScanPlugins(backend.LIME_PACKAGES_PATH, ".py") // for _, p := range plugins { // newPlugin(p, m) // } newPlugin(packages.NewPlugin(path.Join(backend.LIME_PACKAGES_PATH, "Vintageous"), ".py"), m) go watcher.Observe() }
func (t *tbfe) ServeHTTP(w http.ResponseWriter, req *http.Request) { s := time.Now() w.Header().Set("Content-Type", "text/html") log.Debug("Serving client: %s", req) c := scheme.Spice(&render.ViewRegions{}) html, err := ioutil.ReadFile("index.html") if err != nil { w.WriteHeader(404) panic(err) } r := strings.NewReplacer("{{foregroundColor}}", htmlcol(c.Foreground), "{{backgroundColor}}", htmlcol(c.Background)) r.WriteString(w, string(html)) log.Debug("Done serving client: %s", time.Since(s)) }
func (t *tbfe) view(w http.ResponseWriter, req *http.Request) { log.Debug("view: %s", req) if t.dirty { t.dirty = false t.render(w) } else { w.WriteHeader(404) } }
func (ch *commandHandler) RunApplicationCommand(name string, args Args) error { p := Prof.Enter("ac") defer p.Exit() if ch.log { log.Info("Running application command: %s %v", name, args) } else { log.Fine("Running application command: %s %v", name, args) } if c, ok := ch.ApplicationCommands[name].(ApplicationCommand); c != nil && ok { if err := ch.init(c, args); err != nil && ch.verbose { log.Debug("Command initialization failed: %s", err) return err } else if err := c.Run(); err != nil && ch.verbose { log.Debug("Command execution failed: %s", err) return err } } return nil }
func (lp *LanguageParser) Parse() (*parser.Node, error) { sdata := string(lp.data) rn := parser.Node{P: lp, Name: lp.l.ScopeName} defer func() { if r := recover(); r != nil { log.Errorf("Panic during parse: %v\n", r) log.Debug("%v", rn) } }() iter := maxiter for i := 0; i < len(sdata) && iter > 0; iter-- { pat, ret := lp.l.RootPattern.Cache(sdata, i) nl := strings.IndexAny(sdata[i:], "\n\r") if nl != -1 { nl += i } if ret == nil { break } else if nl > 0 && nl <= ret[0] { i = nl for i < len(sdata) && (sdata[i] == '\n' || sdata[i] == '\r') { i++ } } else { n := pat.CreateNode(sdata, i, lp, ret) rn.Append(n) i = n.Range.B } } rn.UpdateRange() if len(sdata) != 0 { lut := make([]int, len(sdata)+1) j := 0 for i := range sdata { lut[i] = j j++ } lut[len(sdata)] = len(lp.data) lp.patch(lut, &rn) } if iter == 0 { panic("reached maximum number of iterations") } return &rn, nil }
func (c *WindowCommandGlue) Run(w *backend.Window) error { l := py.NewLock() defer l.Unlock() var ( pyw, pyargs, obj py.Object err error ) log.Debug("WindowCommand: %v", c.args) if pyw, err = toPython(w); err != nil { return pyError(err) } defer pyw.Decref() if pyargs, err = c.CreatePyArgs(c.args); err != nil { return pyError(err) } defer pyargs.Decref() // interrupt := true // defer func() { interrupt = false }() // go func() { // <-time.After(time.Second * 5) // if interrupt { // py.SetInterrupt() // } // }() if obj, err = c.inner.Base().CallFunctionObjArgs(pyw); err != nil { return pyError(err) } defer obj.Decref() if ret, err := obj.Base().CallMethodObjArgs("run_", pyargs); err != nil { return pyError(err) } else { ret.Decref() } return nil }
func (q *qmlDialog) Show(msg, icon string) (ret int) { src := `import QtQuick 2.2 import QtQuick.Dialogs 1.1 Item {MessageDialog { objectName: "realDialog" id: messageDialog title: "May I have your attention please" text: "` + msg + `" icon: ` + icon + ` standardButtons: StandardButton.Ok | StandardButton.Cancel Component.onCompleted: visible = true }}` engine := qml.NewEngine() engine.Context().SetVar("q", q) component, err := engine.LoadString("dialog.qml", src) if err != nil { log.Error("Unable to instanciate dialog: %s", err) return 0 } var wg sync.WaitGroup wg.Add(1) obj := component.Create(nil) obj = obj.ObjectByName("realDialog") obj.On("accepted", func() { ret = 1 wg.Done() }) obj.On("rejected", func() { ret = 0 wg.Done() }) wg.Wait() engine.Destroy() log.Debug("returning %d", ret) return }
func (t *qmlfrontend) HandleInput(keycode int, modifiers int) bool { log.Debug("qmlfrontend.HandleInput: key=%x, modifiers=%x", keycode, modifiers) shift := false alt := false ctrl := false super := false if key, ok := lut[keycode]; ok { ed := backend.GetEditor() if (modifiers & shift_mod) != 0 { shift = true } if (modifiers & alt_mod) != 0 { alt = true } if (modifiers & ctrl_mod) != 0 { if runtime.GOOS == "darwin" { super = true } else { ctrl = true } } if (modifiers & meta_mod) != 0 { if runtime.GOOS == "darwin" { ctrl = true } else { super = true } } ed.HandleInput(keys.KeyPress{Key: key, Shift: shift, Alt: alt, Ctrl: ctrl, Super: super}) return true } return false }
func (ch *commandHandler) RunWindowCommand(wnd *Window, name string, args Args) error { lvl := log.FINE p := Prof.Enter("wc") defer p.Exit() if ch.log { lvl = log.DEBUG } log.Logf(lvl, "Running window command: %s %v", name, args) t := time.Now() if c, ok := ch.WindowCommands[name].(WindowCommand); c != nil && ok { if err := ch.init(c, args); err != nil && ch.verbose { log.Debug("Command initialization failed: %s", err) return err } else if err := wnd.runCommand(c, name); err != nil { log.Logf(lvl+1, "Command execution failed: %s", err) return err } else { log.Logf(lvl, "Ran Window command: %s %s", name, time.Since(t)) } } else { log.Logf(lvl, "No such window command: %s", name) } return nil }
func (t *tbfe) theme(w http.ResponseWriter, req *http.Request) { log.Debug("theme: %s", req) reqpath, _ := url.QueryUnescape(req.RequestURI) // Make sure the URL starts with "/themes/" // Don't allow ".." in URLs if !strings.HasPrefix(reqpath, "/themes/") || strings.Index(reqpath, "..") != -1 { w.WriteHeader(404) return } filepath := path.Join("../../packages", reqpath) exists := false if s, err := os.Stat(filepath); err == nil { if !s.IsDir() { exists = true } } if exists { fi, err := os.Open(filepath) if err != nil { w.WriteHeader(500) log.Error(err) return } defer fi.Close() io.Copy(w, fi) } else { w.WriteHeader(404) } }
func (t *qmlfrontend) loop() (err error) { backend.OnNew.Add(t.onNew) backend.OnClose.Add(t.onClose) backend.OnLoad.Add(t.onLoad) ed := backend.GetEditor() ed.Init() sublime.Init() ed.SetFrontend(t) ed.LogInput(false) ed.LogCommands(false) c := ed.Console() t.Console = &frontendView{bv: c} c.Buffer().AddCallback(t.Console.bufferChanged) c.Buffer().AddCallback(t.scroll) var ( engine *qml.Engine component qml.Object // WaitGroup keeping track of open windows wg sync.WaitGroup ) // create and setup a new engine, destroying // the old one if one exists. // // This is needed to re-load qml files to get // the new file contents from disc as otherwise // the old file would still be what is referenced. newEngine := func() (err error) { if engine != nil { log.Debug("calling destroy") // TODO(.): calling this appears to make the editor *very* crash-prone, just let it leak for now // engine.Destroy() engine = nil } log.Debug("calling newEngine") engine = qml.NewEngine() log.Debug("setvar frontend") engine.Context().SetVar("frontend", t) log.Debug("setvar editor") engine.Context().SetVar("editor", backend.GetEditor()) log.Debug("loadfile") component, err = engine.LoadFile(qmlMainFile) if err != nil { return err } limeViewComponent, err = engine.LoadFile(qmlViewFile) return } if err := newEngine(); err != nil { log.Error(err) } backend.OnNewWindow.Add(func(w *backend.Window) { fw := &frontendWindow{bw: w} t.windows[w] = fw if component != nil { fw.launch(&wg, component) } }) // TODO: should be done backend side if sc, err := textmate.LoadTheme("../../3rdparty/bundles/TextMate-Themes/Monokai.tmTheme"); err != nil { log.Error(err) } else { scheme = sc } defer func() { fmt.Println(util.Prof) }() w := ed.NewWindow() v := w.OpenFile("main.go", 0) // TODO: should be done backend side v.Settings().Set("syntax", "../../3rdparty/bundles/go.tmbundle/Syntaxes/Go.tmLanguage") v = w.OpenFile("../../backend/editor.go", 0) // TODO: should be done backend side v.Settings().Set("syntax", "../../3rdparty/bundles/go.tmbundle/Syntaxes/Go.tmLanguage") watch, err := fsnotify.NewWatcher() if err != nil { log.Error("Unable to create file watcher: %s", err) return } defer watch.Close() watch.Watch(".") defer watch.RemoveWatch(".") reloadRequested := false go func() { for { select { case ev := <-watch.Event: if ev != nil && strings.HasSuffix(ev.Name, ".qml") && ev.IsModify() && !ev.IsAttrib() { reloadRequested = true // Close all open windows to de-reference all // qml objects for _, v := range t.windows { if v.window != nil { v.window.Hide() v.window.Destroy() v.window = nil } } } } } }() for { // Reset reload status reloadRequested = false log.Debug("Waiting for all windows to close") // wg would be the WaitGroup all windows belong to, so first we wait for // all windows to close. wg.Wait() log.Debug("All windows closed. reloadRequest: %v", reloadRequested) // then we check if there's a reload request in the pipe if !reloadRequested || len(t.windows) == 0 { // This would be a genuine exit; all windows closed by the user break } // *We* closed all windows because we want to reload freshly changed qml // files. for { log.Debug("Calling newEngine") if err := newEngine(); err != nil { // Reset reload status reloadRequested = false log.Error(err) for !reloadRequested { // This loop allows us to re-try reloading // if there was an error in the file this time, // we just loop around again when we receive the next // reload request (ie on the next save of the file). time.Sleep(time.Second) } continue } log.Debug("break") break } log.Debug("re-launching all windows") // Succeeded loading the file, re-launch all windows for _, v := range t.windows { v.launch(&wg, component) } } return }
func (e *Editor) inputthread() { pc := 0 var lastBindings keys.KeyBindings doinput := func(kp keys.KeyPress) { defer func() { if r := recover(); r != nil { log.Error("Panic in inputthread: %v\n%s", r, string(debug.Stack())) if pc > 0 { panic(r) } pc++ } }() p := Prof.Enter("hi") defer p.Exit() lvl := log.FINE if e.logInput { lvl++ } log.Logf(lvl, "Key: %v", kp) if lastBindings.KeyOff() == 0 { lastBindings = e.keyBindings } try_again: possible_actions := lastBindings.Filter(kp) lastBindings = possible_actions // TODO? var ( wnd *Window v *View ) if wnd = e.ActiveWindow(); wnd != nil { v = wnd.ActiveView() } qc := func(key string, operator Op, operand interface{}, match_all bool) bool { return OnQueryContext.Call(v, key, operator, operand, match_all) == True } if action := possible_actions.Action(qc); action != nil { p2 := Prof.Enter("hi.perform") e.RunCommand(action.Command, action.Args) p2.Exit() } else if possible_actions.KeyOff() > 1 { lastBindings = e.keyBindings goto try_again } else if kp.IsCharacter() { p2 := Prof.Enter("hi.character") log.Finest("kp: %v, pos: %v", kp, possible_actions) if err := e.CommandHandler().RunTextCommand(v, "insert", Args{"characters": string(rune(kp.Key))}); err != nil { log.Debug("Couldn't run textcommand: %s", err) } p2.Exit() } } for kp := range e.keyInput { doinput(kp) } }
func (t *tbfe) WebsocketServer(ws *websocket.Conn) { clients = append(clients, ws) // Send status message if t.status_message != "" { websocket.JSON.Send(ws, map[string]string{"type": "statusMessage", "msg": t.status_message}) } // Send cursor position websocket.JSON.Send(ws, t.GetSelectionMessage(backend.GetEditor().ActiveWindow().ActiveView())) // Send editor content var buf bytes.Buffer t.render(bufio.NewWriter(&buf)) websocket.Message.Send(ws, buf.Bytes()) buf.Reset() var data map[string]interface{} var kp keys.KeyPress for { err := websocket.JSON.Receive(ws, &data) if err != nil { log.Error(err) return } //log.LogDebug("Received: %s", data) msgType := data["type"].(string) if msgType == "key" { kp.Alt = data["altKey"].(bool) kp.Ctrl = data["ctrlKey"].(bool) kp.Super = data["metaKey"].(bool) kp.Shift = data["shiftKey"].(bool) if keyName, ok := data["key"].(string); ok { if utf8.RuneCountInString(keyName) == 1 { // One char r, _ := utf8.DecodeRuneInString(keyName) kp.Key = keys.Key(int64(r)) } else { // TODO: automatic lookup instead of this manual lookup // See https://github.com/limetext/lime/pull/421/files#r19269236 keymap := map[string]keys.Key{ "ArrowLeft": keys.Left, "ArrowUp": keys.Up, "ArrowRight": keys.Right, "ArrowDown": keys.Down, "Left": keys.Left, "Up": keys.Up, "Right": keys.Right, "Down": keys.Down, "Enter": keys.Enter, "Escape": keys.Escape, "Backspace": keys.Backspace, "Delete": keys.Delete, "Del": keys.Delete, // Deprecated: some old browsers still use "Del" instead of "Delete" "KeypadEnter": keys.KeypadEnter, "F1": keys.F1, "F2": keys.F2, "F3": keys.F3, "F4": keys.F4, "F5": keys.F5, "F6": keys.F6, "F7": keys.F7, "F8": keys.F8, "F9": keys.F9, "F10": keys.F10, "F11": keys.F11, "F12": keys.F12, "Insert": keys.Insert, "PageUp": keys.PageUp, "PageDown": keys.PageDown, "Home": keys.Home, "End": keys.End, "Break": keys.Break, } if key, ok := keymap[keyName]; ok { kp.Key = key } else { log.Debug("Unknown key: %s", keyName) continue } } } else { v := int64(data["keyCode"].(float64)) if !kp.Shift { v = int64(unicode.ToLower(rune(v))) } kp.Key = keys.Key(v) } backend.GetEditor().HandleInput(kp) } else if msgType == "command" { command := data["name"].(string) //args := data["args"].([]string) //TODO: add arguments support ed := backend.GetEditor() go ed.RunCommand(command, make(backend.Args)) } else { log.Info("Unhandled message type: %s", msgType) } } }
func (t *tbfe) loop() { backend.OnNew.Add(func(v *backend.View) { v.Settings().AddOnChange("lime.frontend.html.render", func(name string) { if name != "lime.syntax.updated" { return } t.SetDirty() }) }) // TODO: maybe not useful? /*backend.OnModified.Add(func(v *backend.View) { t.SetDirty() })*/ backend.OnSelectionModified.Add(func(v *backend.View) { t.BroadcastData(t.GetSelectionMessage(v)) }) ed := backend.GetEditor() ed.SetFrontend(t) ed.LogInput(false) ed.LogCommands(false) c := ed.Console() if sc, err := textmate.LoadTheme("../../packages/themes/TextMate-Themes/Monokai.tmTheme"); err != nil { log.Error(err) } else { scheme = sc } defer func() { fmt.Println(util.Prof) }() w := ed.NewWindow() v := w.OpenFile("main.go", 0) //v.Settings().Set("trace", true) v.Settings().Set("syntax", "../../packages/go.tmbundle/Syntaxes/Go.tmLanguage") c.Buffer().AddObserver(t) sel := v.Sel() sel.Clear() // end := v.Buffer().Size() - 2 sel.Add(Region{0, 0}) // sel.Add(Region{end - 22, end - 22}) // sel.Add(Region{end - 16, end - 20}) // sel.Add(Region{end - 13, end - 10}) { w, h := 800, 600 t.lock.Lock() t.layout[v] = layout{0, 0, w, h - console_height - 1, Region{}, 0} t.layout[c] = layout{0, h - console_height + 1, w, console_height - 5, Region{}, 0} t.lock.Unlock() t.Show(v, Region{1, 1}) } t.Show(v, Region{100, 100}) t.Show(v, Region{1, 1}) go func() { ed.Init() sublime.Init() }() log.Debug("Serving on port %d", *port) http.HandleFunc("/", t.ServeHTTP) http.HandleFunc("/view", t.view) http.HandleFunc("/key", t.key) http.HandleFunc("/themes/", t.theme) http.Handle("/ws", websocket.Handler(t.WebsocketServer)) if err := http.ListenAndServe(fmt.Sprintf("localhost:%d", *port), nil); err != nil { log.Errorf("Error serving: %s", err) } log.Debug("Done") }
func TestSublime(t *testing.T) { ed := backend.GetEditor() ed.SetClipboardFuncs(func(n string) (err error) { dummyClipboard = n return nil }, func() (string, error) { return dummyClipboard, nil }) defer ed.Init() ed.Console().Buffer().AddCallback(func(b text.Buffer, pos, delta int) { t.Logf("%s", b.Substr(text.Region{pos, pos + delta})) }) w := ed.NewWindow() Init() l := py.NewLock() py.AddToPath("testdata") py.AddToPath("testdata/plugins") if m, err := py.Import("sublime_plugin"); err != nil { t.Fatal(err) } else { plugins := packages.ScanPlugins("testdata/", ".py") for _, p := range plugins { pl := newPlugin(p, m) pl.reload() if err := watcher.Watch(pl.Name(), pl); err != nil { t.Fatalf("Couldn't watch %s: %s", pl.Name(), err) } } } subl, err := py.Import("sublime") if err != nil { t.Fatal(err) } if w, err := _windowClass.Alloc(1); err != nil { t.Fatal(err) } else { (w.(*Window)).data = &backend.Window{} subl.AddObject("test_window", w) } // Testing plugin reload data := []byte(`import sublime, sublime_plugin class TestToxt(sublime_plugin.TextCommand): def run(self, edit): print("my view's id is: %d" % self.view.id()) self.view.insert(edit, 0, "Tada") `) if err := ioutil.WriteFile("testdata/plugins/reload.py", data, 0644); err != nil { t.Fatalf("Couldn't write testdata/plugins/reload.py: %s", err) } defer os.Remove("testdata/plugins/reload.py") time.Sleep(time.Millisecond * 50) if dir, err := os.Open("testdata"); err != nil { t.Error(err) } else if files, err := dir.Readdirnames(0); err != nil { t.Error(err) } else { for _, fn := range files { if filepath.Ext(fn) == ".py" { log.Debug("Running %s", fn) if _, err := py.Import(fn[:len(fn)-3]); err != nil { log.Error(err) t.Error(err) } else { log.Debug("Ran %s", fn) } } } } var f func(indent string, v py.Object, buf *bytes.Buffer) f = func(indent string, v py.Object, buf *bytes.Buffer) { b := v.Base() if dir, err := b.Dir(); err != nil { t.Error(err) } else { if l, ok := dir.(*py.List); ok { sl := l.Slice() if indent == "" { for _, v2 := range sl { if item, err := b.GetAttr(v2); err != nil { t.Error(err) } else { ty := item.Type() line := fmt.Sprintf("%s%s\n", indent, v2) buf.WriteString(line) if ty == py.TypeType { f(indent+"\t", item, buf) } item.Decref() } } } else { for _, v2 := range sl { buf.WriteString(fmt.Sprintf("%s%s\n", indent, v2)) } } } else { ty := dir.Type() t.Error("Unexpected type:", ty) } dir.Decref() } } buf := bytes.NewBuffer(nil) f("", subl, buf) l.Unlock() const expfile = "testdata/api.txt" if d, err := ioutil.ReadFile(expfile); err != nil { if err := ioutil.WriteFile(expfile, buf.Bytes(), 0644); err != nil { t.Error(err) } } else if diff := util.Diff(string(d), buf.String()); diff != "" { t.Error(diff) } ed.LogCommands(true) tests := []string{ "state", "registers", "settings", "constants", "registers", "cmd_data", "marks", } for _, test := range tests { ed.CommandHandler().RunWindowCommand(w, "vintage_ex_run_data_file_based_tests", backend.Args{"suite_name": test}) } for _, w := range ed.Windows() { for _, v := range w.Views() { if strings.HasSuffix(v.Buffer().FileName(), "sample.txt") { continue } if strings.Index(v.Buffer().Substr(text.Region{0, v.Buffer().Size()}), "FAILED") != -1 { t.Error(v.Buffer()) } } } var v *backend.View for _, v2 := range w.Views() { if v == nil || v2.Buffer().Size() > v.Buffer().Size() { v = v2 } } }