Example #1
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()
}
Example #2
0
func GetEditor() *Editor {
	edl.Lock()
	defer edl.Unlock()
	if ed == nil {
		ed = &Editor{
			cmdHandler: commandHandler{
				ApplicationCommands: make(appcmd),
				TextCommands:        make(textcmd),
				WindowCommands:      make(wndcmd),
				verbose:             true,
			},
			frontend: &DummyFrontend{},
			console: &View{
				buffer:  NewBuffer(),
				scratch: true,
			},
			keyInput: make(chan keys.KeyPress, 32),
		}
		var err error
		if ed.Watcher, err = watch.NewWatcher(); err != nil {
			log.Errorf("Couldn't create watcher: %s", err)
		}
		ed.console.Settings().Set("is_widget", true)
		ed.defaultSettings = new(HasSettings)
		ed.platformSettings = new(HasSettings)
		ed.Settings() // Just to initialize it
		ed.defaultBindings = new(keys.HasKeyBindings)
		ed.platformBindings = new(keys.HasKeyBindings)
		ed.userBindings = new(keys.HasKeyBindings)
		log.AddFilter("console", log.DEBUG, log.NewLogWriter(ed.handleLog))
		go ed.inputthread()
		go ed.Observe()
	}
	return ed
}
Example #3
0
func (w *Window) OpenFile(filename string, flags int) *View {
	v := w.NewFile()

	v.SetScratch(true)
	e := v.BeginEdit()
	if fn, err := filepath.Abs(filename); err != nil {
		v.Buffer().SetFileName(filename)
	} else {
		v.Buffer().SetFileName(fn)
	}
	if d, err := ioutil.ReadFile(filename); err != nil {
		log.Errorf("Couldn't load file %s: %s", filename, err)
	} else {
		v.Insert(e, 0, string(d))
	}
	v.EndEdit(e)
	v.selection.Clear()
	v.selection.Add(text.Region{A: 0, B: 0})
	v.Settings().Set("lime.last_save_change_count", v.buffer.ChangeCount())
	v.SetScratch(false)

	OnLoad.Call(v)
	w.SetActiveView(v)

	return v
}
Example #4
0
func registerByName(cmds []namedCmd) {
	ch := backend.GetEditor().CommandHandler()
	for _, cmd := range cmds {
		if err := ch.Register(cmd.name, cmd.cmd); err != nil {
			log.Errorf("Failed to register command %s: %s", cmd.name, err)
		}
	}
}
Example #5
0
func (w *Window) runCommand(c WindowCommand, name string) error {
	defer func() {
		if r := recover(); r != nil {
			log.Errorf("Paniced while running window command %s %v: %v\n%s", name, c, r, string(debug.Stack()))
		}
	}()
	return c.Run(w)
}
Example #6
0
func (e *Editor) SetClipboard(n string) {
	if err := e.clipboardSetter(n); err != nil {
		log.Errorf("Could not set clipboard: %v", err)
	}

	// Keep a local copy in case the system clipboard isn't working
	e.clipboard = n
}
Example #7
0
func register(cmds []backend.Command) {
	ch := backend.GetEditor().CommandHandler()
	for _, cmd := range cmds {
		if err := ch.RegisterWithDefault(cmd); err != nil {
			log.Errorf("Failed to register command: %s", err)
		}
	}
}
Example #8
0
func (e *Editor) GetClipboard() string {
	if n, err := e.clipboardGetter(); err == nil {
		return n
	} else {
		log.Errorf("Could not get clipboard: %v", err)
	}

	return e.clipboard
}
Example #9
0
func (e *Editor) load(pkg *packages.Packet) {
	if err := pkg.Load(); err != nil {
		log.Errorf("Failed to load packet %s: %s", pkg.Name(), err)
	} else {
		log.Info("Loaded %s", pkg.Name())
		if err := e.Watch(pkg.Name(), pkg); err != nil {
			log.Warn("Couldn't watch %s: %s", pkg.Name(), err)
		}
	}
}
Example #10
0
func newPlugin(pl *packages.Plugin, m *py.Module) (p *plugin) {
	p = &plugin{pl, m}
	p.FileChanged(p.Name())
	if err := watcher.Watch(p.Name(), p); err != nil {
		log.Errorf("Couldn't watch %s: %s", p.Name(), err)
	}
	p.loadKeyBindings()
	p.loadSettings()
	return
}
Example #11
0
// On plugin reload we will scan for plugin files
// and packets in plugin path
func (p *Plugin) Reload() {
	var files []os.FileInfo
	log.Info("Reloading plugin %s", p.Name())
	f, err := os.Open(p.path)
	if err != nil {
		log.Errorf("Couldn't open dir: %s", err)
		return
	}
	defer f.Close()
	fi, err := f.Readdir(-1)
	if err != nil {
		log.Errorf("Couldn't read dir: %s", err)
		return
	}
	for _, f := range fi {
		if p.suffix != "" && strings.HasSuffix(f.Name(), p.suffix) {
			files = append(files, f)
		}
	}
	p.files = files
}
Example #12
0
func (e *Editor) remove(w *Window) {
	edl.Lock()
	defer edl.Unlock()
	for i, ww := range e.windows {
		if w == ww {
			end := len(e.windows) - 1
			if i != end {
				copy(e.windows[i:], e.windows[i+1:])
			}
			e.windows = e.windows[:end]
			return
		}
	}
	log.Errorf("Wanted to remove window %+v, but it doesn't appear to be a child of this editor", w)
}
Example #13
0
func (w *Window) remove(v *View) {
	w.lock.Lock()
	defer w.lock.Unlock()
	for i, vv := range w.views {
		if v == vv {
			end := len(w.views) - 1
			if i != end {
				copy(w.views[i:], w.views[i+1:])
			}
			w.views = w.views[:end]
			return
		}
	}
	log.Errorf("Wanted to remove view %+v, but it doesn't appear to be a child of this window", v)
}
Example #14
0
func (v *View) runCommand(cmd TextCommand, name string) error {
	e := v.BeginEdit()
	e.command = name
	//	e.args = args
	e.bypassUndo = cmd.BypassUndo()

	defer func() {
		v.EndEdit(e)
		if r := recover(); r != nil {
			log.Errorf("Paniced while running text command %s %v: %v\n%s", name, cmd, r, string(debug.Stack()))
		}
	}()
	p := Prof.Enter("view.cmd." + name)
	defer p.Exit()
	return cmd.Run(v, e)
}
Example #15
0
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
}
Example #16
0
// Returns packet file data if any error occurred
// on reading file we will return nil
func (p *Packet) Get() interface{} {
	e := []byte(`{}`)
	if p.group() == "keymap" {
		e = []byte(`[]`)
	}

	if _, err := os.Stat(p.path); os.IsNotExist(err) {
		log.Finest("%s doesn't exist yet", p.path)
		return e
	}

	d, err := ioutil.ReadFile(p.path)
	if err != nil {
		log.Errorf("Couldn't read file: %s", err)
		return e
	}
	return d
}
Example #17
0
func (v *View) FileChanged(filename string) {
	log.Finest("Reloading %s", filename)

	if saving, ok := v.Settings().Get("lime.saving", false).(bool); ok && saving {
		// This reload was triggered by ourselves saving to this file, so don't reload it
		return
	}
	if !GetEditor().Frontend().OkCancelDialog("File was changed by another program, reload?", "reload") {
		return
	}

	if d, err := ioutil.ReadFile(filename); err != nil {
		log.Errorf("Could not read file: %s\n. Error was: %v", filename, err)
	} else {
		edit := v.BeginEdit()
		end := v.buffer.Size()
		v.Replace(edit, Region{0, end}, string(d))
		v.EndEdit(edit)
	}
}
Example #18
0
// Ends the given Edit object.
func (v *View) EndEdit(edit *Edit) {
	if edit.invalid {
		// This happens when nesting Edits and the child Edit ends after the parent edit.
		log.Fine("This edit has already been invalidated: %v, %v", edit, v.editstack)
		return
	}

	// Find the position of this Edit object in this View's Edit stack.
	// If plugins, commands, etc are well-behaved the ended edit should be
	// last in the stack, but shit happens and we cannot count on this being the case.
	i := len(v.editstack) - 1
	for i := len(v.editstack) - 1; i >= 0; i-- {
		if v.editstack[i] == edit {
			break
		}
	}
	if i == -1 {
		// TODO(.): Under what instances does this happen again?
		log.Errorf("This edit isn't even in the stack... where did it come from? %v, %v", edit, v.editstack)
		return
	}

	var selection_modified bool

	if l := len(v.editstack) - 1; i != l {
		// TODO(.): See TODO in BeginEdit
		log.Errorf("This edit wasn't last in the stack... %d !=  %d: %v, %v", i, l, edit, v.editstack)
	}

	// Invalidate all Edits "below" and including this Edit.
	for j := len(v.editstack) - 1; j >= i; j-- {
		current_edit := v.editstack[j]
		current_edit.invalid = true
		sel_same := reflect.DeepEqual(*v.Sel(), current_edit.savedSel)
		buf_same := v.buffer.ChangeCount() == current_edit.savedCount
		eq := (sel_same && buf_same && current_edit.composite.Len() == 0)
		if !eq && !sel_same {
			selection_modified = true
		}
		if v.IsScratch() || current_edit.bypassUndo || eq {
			continue
		}
		switch {
		case i == 0:
			// Well-behaved, no nested edits!
			fallthrough
		case j != i:
			// BOO! Someone began another Edit without finishing the first one.
			// In this instance, the parent Edit ended before the child.
			// TODO(.): What would be the correct way to handle this?
			v.undoStack.Add(edit)
		default:
			// BOO! Also poorly-behaved. This Edit object began after the parent began,
			// but was finished before the parent finished.
			//
			// Add it as a child of the parent Edit so that undoing the parent
			// will undo this edit as well.
			v.editstack[i-1].composite.Add(current_edit)
		}
	}
	// Pop this Edit and all the children off the Edit stack.
	v.editstack = v.editstack[:i]
	if selection_modified {
		OnSelectionModified.Call(v)
	}
}
Example #19
0
func (e *Editor) inputthread() {
	pc := 0
	var lastBindings keys.KeyBindings
	doinput := func(kp keys.KeyPress) {
		defer func() {
			if r := recover(); r != nil {
				log.Errorf("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)
	}
}
Example #20
0
// parsethread() would be the go-routine used for dealing with reparsing the
// current buffer when it has been modified. Each opened view has its own
// go-routine parsethread() which sits idle and waits for requests to be sent
// on this view's reparseChan.
//
// The Buffer's ChangeCount, as well as the parse request's "forced" attribute
// is used to determined if a parse actually needs to happen or not.
//
// If it is decided that a reparse should take place, a snapshot of the Buffer is
// taken and a parse is performed. Upon completion of this parse operation,
// and if the snapshot of the buffer has not already become outdated,
// then the regions of the view associated with syntax highlighting is updated.
//
// Changes made to the Buffer during the time when there is no accurate
// parse of the buffer is a monkey-patched version of the old syntax highlighting
// regions, which in most instances will be accurate.
//
// See package lime-backend/lib/parser for more details.
func (v *View) parsethread() {
	pc := 0
	lastParse := -1
	doparse := func() (ret bool) {
		p := Prof.Enter("syntax.parse")
		defer p.Exit()
		defer func() {
			if r := recover(); r != nil {
				log.Errorf("Panic in parse thread: %v\n%s", r, string(debug.Stack()))
				if pc > 0 {
					panic(r)
				}
				pc++
			}
		}()

		b := v.buffer
		sub := b.Substr(Region{0, b.Size()})

		source, _ := v.Settings().Get("syntax", "").(string)
		if len(source) == 0 {
			return
		}

		// TODO: Allow other parsers instead of this hardcoded textmate version
		pr, err := textmate.NewLanguageParser(source, sub)
		if err != nil {
			log.Errorf("Couldn't parse: %v", err)
			return
		}

		syn, err := parser.NewSyntaxHighlighter(pr)
		if err != nil {
			log.Errorf("Couldn't create syntaxhighlighter: %v", err)
			return
		}

		// Only set if it isn't invalid already, otherwise the
		// current syntax highlighting will be more accurate
		// as it will have had incremental adjustments done to it
		if v.buffer.ChangeCount() != lastParse {
			return
		}

		v.lock.Lock()
		defer v.lock.Unlock()

		v.syntax = syn
		for k := range v.regions {
			if strings.HasPrefix(k, "lime.syntax") {
				delete(v.regions, k)
			}
		}

		for k, v2 := range syn.Flatten() {
			if v2.Regions.HasNonEmpty() {
				v.regions[k] = v2
			}
		}

		return true
	}

	v.lock.Lock()
	ch := v.reparseChan
	v.lock.Unlock()
	defer v.cleanup()
	if ch == nil {
		return
	}

	for pr := range ch {
		if cc := v.buffer.ChangeCount(); lastParse != cc || pr.forced {
			lastParse = cc
			if doparse() {
				v.Settings().Set("lime.syntax.updated", lastParse)
			}
		}
	}
}