コード例 #1
0
ファイル: editor.go プロジェクト: yzq1979/lime-backend
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")
	}
}
コード例 #2
0
ファイル: events.go プロジェクト: sivaramanr/lime-backend
// Execute the InitEvent.
func (ie *InitEvent) call() {
	log.Debug("OnInit callbacks executing")
	defer log.Debug("OnInit callbacks finished")
	for _, ev := range *ie {
		ev()
	}
}
コード例 #3
0
ファイル: main.go プロジェクト: yzq1979/lime-termbox
func setColorMode() {
	var (
		mode256 bool
		pal     = make([]termbox.RGB, 0, 256)
	)

	if err := termbox.SetColorMode(termbox.ColorMode256); err != nil {
		log.Errorf("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{R: 0, G: 0, B: 0}
		pal[termbox.ColorWhite] = termbox.RGB{R: 255, G: 255, B: 255}
		pal[termbox.ColorRed] = termbox.RGB{R: 255, G: 0, B: 0}
		pal[termbox.ColorGreen] = termbox.RGB{R: 0, G: 255, B: 0}
		pal[termbox.ColorBlue] = termbox.RGB{R: 0, G: 0, B: 255}
		pal[termbox.ColorMagenta] = termbox.RGB{R: 255, G: 0, B: 255}
		pal[termbox.ColorYellow] = termbox.RGB{R: 255, G: 255, B: 0}
		pal[termbox.ColorCyan] = termbox.RGB{R: 0, G: 255, B: 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{R: col.R, G: col.G, B: 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)
		}
	}
}
コード例 #4
0
ファイル: main.go プロジェクト: yzq1979/lime-termbox
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()
	}
}
コード例 #5
0
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()
}
コード例 #6
0
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)
}
コード例 #7
0
ファイル: main.go プロジェクト: yzq1979/lime-html
// 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)
}
コード例 #8
0
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
}
コード例 #9
0
ファイル: main.go プロジェクト: yzq1979/lime-termbox
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()
	go t.editor.Init()
	t.loop()
}
コード例 #10
0
ファイル: main.go プロジェクト: yzq1979/lime-html
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)
	}
}
コード例 #11
0
ファイル: main.go プロジェクト: yzq1979/lime-html
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))
}
コード例 #12
0
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
}
コード例 #13
0
ファイル: language.go プロジェクト: modulexcite/lime-backend
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
}
コード例 #14
0
ファイル: watch.go プロジェクト: sivaramanr/lime-backend
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.Fine("%s doesn't exist, Watching parent directory", name)
		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 {
			return err
		}
		if exist(w.dirs, name) {
			log.Debug("%s is watched already", name)
			return nil
		}
	}
	// 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
}
コード例 #15
0
ファイル: qml_dialog.go プロジェクト: bianshifeng/lime-qml
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
}
コード例 #16
0
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
}
コード例 #17
0
ファイル: main.go プロジェクト: yzq1979/lime-html
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(backend.LIME_PACKAGES_PATH, 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)
	}
}
コード例 #18
0
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
}
コード例 #19
0
ファイル: qml_frontend.go プロジェクト: yzq1979/lime-qml
func (t *qmlfrontend) HandleInput(text string, keycode int, modifiers int) bool {
	log.Debug("qmlfrontend.HandleInput: text=%v, key=%x, modifiers=%x", text, 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{Text: text, Key: key, Shift: shift, Alt: alt, Ctrl: ctrl, Super: super})
		return true
	}
	return false
}
コード例 #20
0
ファイル: main.go プロジェクト: yzq1979/lime-html
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(path.Join(backend.LIME_PACKAGES_PATH, "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", path.Join(backend.LIME_PACKAGES_PATH, "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 ed.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")
}
コード例 #21
0
ファイル: main.go プロジェクト: yzq1979/lime-html
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)
				kp.Text = string(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)
		}
	}
}
コード例 #22
0
ファイル: editor.go プロジェクト: yzq1979/lime-backend
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.SeqIndex() == 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.SeqIndex() > 1 {
			// TODO: this disables having keyBindings with more than 2 key sequence
			lastBindings = *e.KeyBindings()
			goto try_again
		} else if kp.IsCharacter() {
			p2 := Prof.Enter("hi.character")
			log.Finest("[editor.inputthread] kp: |%s|, pos: %v", kp.Text, possible_actions)
			if err := e.CommandHandler().RunTextCommand(v, "insert", Args{"characters": kp.Text}); err != nil {
				log.Debug("Couldn't run textcommand: %s", err)
			}
			p2.Exit()
		}
	}
	for kp := range e.keyInput {
		doinput(kp)
	}
}
コード例 #23
0
ファイル: qml_frontend.go プロジェクト: yzq1979/lime-qml
func (t *qmlfrontend) loop() (err error) {
	backend.OnNew.Add(t.onNew)
	backend.OnClose.Add(t.onClose)
	backend.OnLoad.Add(t.onLoad)
	backend.OnSelectionModified.Add(t.onSelectionModified)

	ed := backend.GetEditor()
	ed.SetFrontend(t)
	ed.LogInput(false)
	ed.LogCommands(false)
	c := ed.Console()
	t.Console = &frontendView{bv: c}
	c.Buffer().AddObserver(t.Console)
	c.Buffer().AddObserver(t)
	go ed.Init()

	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()
		engine.On("quit", t.Quit)
		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("../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)
	// TODO: should be done backend side
	v.SetSyntaxFile("../packages/go.tmbundle/Syntaxes/Go.tmLanguage")

	watch, err := fsnotify.NewWatcher()
	if err != nil {
		log.Errorf("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
					t.Quit()
				}
			}
		}
	}()

	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
}
コード例 #24
0
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
	})
	ed.Init()

	ed.Console().Buffer().AddObserver(&consoleObserver{T: t})
	w := ed.NewWindow()
	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 {
			newPlugin(p, m)
		}
	}

	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 {
			// FIXME: Skip reload_test.py to work around #531 on OSX.
			if fn == "reload_test.py" && ed.Platform() == "darwin" {
				continue
			}

			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{A: 0, B: 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
		}
	}
}