Beispiel #1
0
func main() {
	flag.Parse()

	log.AddFilter("file", log.FINEST, log.NewFileLogWriter("debug.log", *rotateLog))
	// Replace Global Logger filter so that it does not interfere with the ui
	log.AddFilter("stdout", log.DEBUG, log.NewFileLogWriter("debug.log", *rotateLog))

	defer func() {
		py.NewLock()
		py.Finalize()
	}()

	if err := termbox.Init(); err != nil {
		log.Error(err)
		log.Close()
		return
	}

	defer func() {
		termbox.Close()
		log.Debug(util.Prof)
		if err := recover(); err != nil {
			log.Critical(err)
			panic(err)
		}
	}()

	t := createFrontend()
	t.editor.Init()
	go t.renderthread()
	t.loop()
}
Beispiel #2
0
func (t *tbfe) renderthread() {
	pc := 0
	dorender := func() {
		defer func() {
			if r := recover(); r != nil {
				log.Error("Panic in renderthread: %v\n%s", r, string(debug.Stack()))
				if pc > 1 {
					panic(r)
				}
				pc++
			}
		}()
		termbox.Clear(defaultFg, defaultBg)

		t.lock.Lock()
		vs := make([]*backend.View, 0, len(t.layout))
		ls := make([]layout, 0, len(t.layout))
		for v, l := range t.layout {
			vs = append(vs, v)
			ls = append(ls, l)
		}
		t.lock.Unlock()

		for i, v := range vs {
			t.renderView(v, ls[i])
		}

		termbox.Flush()
	}

	for range t.dorender {
		dorender()
	}
}
Beispiel #3
0
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{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 render.Colour) 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 render.Colour) 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)
		}
	}
}
Beispiel #4
0
// called when a view has loaded
func (f *frontend) onLoad(bv *backend.View) {
	w := f.windows[bv.Window()]
	v := w.views[bv]
	if v == nil {
		log.Error("Couldn't find loaded view")
		return
	}
	v.Title = bv.FileName()
	w.qw.Call("setTabTitle", v.id, v.Title)
}
Beispiel #5
0
// called when a view is closed
func (f *frontend) onClose(bv *backend.View) {
	w := f.windows[bv.Window()]
	v := w.views[bv]
	if v == nil {
		log.Error("Couldn't find closed view...")
		return
	}
	w.qw.Call("removeTab", v.id)
	delete(w.views, bv)
}
Beispiel #6
0
func setSchemeSettings(ed *backend.Editor) {
	s := ed.GetColorScheme(ed.Settings().Get("color_scheme", "").(string))

	if s == nil {
		log.Error("No colour scheme to set defaults from")
		return
	}

	defaultFg = palLut(s.Global().Foreground)
	defaultBg = palLut(s.Global().Background)
}
Beispiel #7
0
func (f *frontend) onStatusChanged(bv *backend.View) {
	w := f.windows[bv.Window()]
	v := w.views[bv]
	if v == nil {
		log.Error("Couldn't find status changed view")
		return
	}
	if v.qv == nil {
		return
	}
	v.qv.Call("onStatusChanged")
}
Beispiel #8
0
func (f *frontend) onSelectionModified(bv *backend.View) {
	w := f.windows[bv.Window()]
	v := w.views[bv]
	if v == nil {
		log.Error("Couldn't find modified view")
		return
	}
	if v.qv == nil {
		return
	}
	v.qv.Call("onSelectionModified")
}
Beispiel #9
0
func (f *frontend) loop() (err error) {
	ed := backend.GetEditor()
	// TODO: As InitCallback doc says initiation code to be deferred until
	// after the UI is up and running. but because we dont have any
	// scheme we are initing editor before the UI comes up.
	ed.Init()
	ed.SetDefaultPath("../packages/Default")
	ed.SetUserPath("../packages/User")
	ed.SetClipboardFuncs(clipboard.WriteAll, clipboard.ReadAll)

	// Some packages(e.g Vintageos) need available window and view at start
	// so we need at least one window and view before loading packages.
	// Sublime text also has available window view on startup
	w := ed.NewWindow()
	w.NewFile()
	ed.AddPackagesPath("../packages")

	ed.SetFrontend(f)
	ed.LogInput(false)
	ed.LogCommands(false)

	c := ed.Console()
	f.Console = newView(c)
	c.AddObserver(f.Console)
	c.AddObserver(f)

	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", f.Quit)
		log.Fine("setvar frontend")
		engine.Context().SetVar("frontend", f)

		log.Fine("loading %s", qmlWindowFile)
		component, err = engine.LoadFile(qmlWindowFile)
		return
	}
	if err := newEngine(); err != nil {
		log.Error("Error on creating new engine: %s", err)
		panic(err)
	}

	addWindow := func(bw *backend.Window) {
		w := newWindow(bw)
		f.windows[bw] = w
		w.launch(&wg, component)
	}

	backend.OnNew.Add(f.onNew)
	backend.OnClose.Add(f.onClose)
	backend.OnLoad.Add(f.onLoad)
	backend.OnSelectionModified.Add(f.onSelectionModified)
	backend.OnNewWindow.Add(addWindow)
	backend.OnStatusChanged.Add(f.onStatusChanged)

	// we need to add windows and views that are added before we registered
	// actions for OnNewWindow and OnNew events
	for _, w := range ed.Windows() {
		addWindow(w)
		for _, v := range w.Views() {
			f.onNew(v)
			f.onLoad(v)
		}
	}

	defer func() {
		fmt.Println(util.Prof)
	}()

	// The rest of code is related to livereloading qml files
	// TODO: this doesnt work currently
	watch, err := fsnotify.NewWatcher()
	if err != nil {
		log.Error("Unable to create file watcher: %s", err)
		return
	}
	defer watch.Close()
	watch.Add("qml")
	defer watch.Remove("qml")

	reloadRequested := false
	waiting := false

	go func() {
		// reloadRequested = true
		// f.Quit()

		lastTime := time.Now()

		for {

			select {
			case ev := <-watch.Events:
				if time.Now().Sub(lastTime) < 1*time.Second {
					// quitting too frequently causes crashes
					lastTime = time.Now()
					continue
				}
				if strings.HasSuffix(ev.Name, ".qml") && ev.Op == fsnotify.Write && ev.Op != fsnotify.Chmod && !reloadRequested && waiting {
					reloadRequested = true
					f.Quit()
					lastTime = time.Now()
				}
			}
		}
	}()

	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.
		waiting = true
		wg.Wait()
		waiting = false
		log.Debug("All windows closed. reloadRequest: %v", reloadRequested)
		// then we check if there's a reload request in the pipe
		if !reloadRequested || len(f.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
				waiting = true
				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)
				}
				waiting = false
				continue
			}
			log.Debug("break")
			break
		}
		log.Debug("re-launching all windows")
		// Succeeded loading the file, re-launch all windows
		for _, w := range f.windows {
			w.launch(&wg, component)

			for _, bv := range w.Back().Views() {
				f.onNew(bv)
				f.onLoad(bv)

			}
		}
	}

	return
}
Beispiel #10
0
func (f *frontend) ErrorMessage(msg string) {
	log.Error(msg)
	f.message(msg, criticalIcon, okButton)
}
Beispiel #11
0
func (t *tbfe) ErrorMessage(msg string) {
	log.Error(msg)
}