func (t *tbfe) VisibleRegion(v *backend.View) Region { t.lock.Lock() r, ok := t.layout[v] t.lock.Unlock() if !ok || r.lastUpdate != v.Buffer().ChangeCount() { t.Show(v, r.visible) t.lock.Lock() r = t.layout[v] t.lock.Unlock() } return r.visible }
func new_view(v *backend.View) { log4go.Debug("new_view entered") defer log4go.Debug("new_view exited") qw := wnds[v.Window()] w := newQLimeView(v) v.Settings().Set("syntax", "../../3rdparty/bundles/GoSublime/GoSublime.tmLanguage") w.SetSizev(600, 400) // w := qt5.NewWidget() sa := qt5.NewScrollArea() sa.SetWidget(w) qw.tw.AddTab(sa, v.Buffer().Name(), nil) }
func (t *tbfe) FormatLine(v *backend.View, line int) string { buf := bytes.NewBuffer(nil) vr := v.Buffer().Line(v.Buffer().TextPoint(line, 0)) log4go.Debug("FormatLine: %d, %s", line, vr) if vr.Size() == 0 { return "" } recipie := v.Transform(scheme, vr).Transcribe() highlight_line := false if b, ok := v.Settings().Get("highlight_line", highlight_line).(bool); ok { highlight_line = b } lastEnd := vr.Begin() for _, reg := range recipie { if lastEnd != reg.Region.Begin() { fmt.Fprintf(buf, "<span>%s</span>", v.Buffer().Substr(Region{lastEnd, reg.Region.Begin()})) } fmt.Fprintf(buf, "<span style=\"white-space:pre; color:#%s; background:#%s\">%s</span>", htmlcol(reg.Flavour.Foreground), htmlcol(reg.Flavour.Background), v.Buffer().Substr(reg.Region)) lastEnd = reg.Region.End() } if lastEnd != vr.End() { io.WriteString(buf, v.Buffer().Substr(Region{lastEnd, vr.End()})) } return buf.String() }
func (t *tbfe) clip(v *backend.View, s, e int) Region { p := util.Prof.Enter("clip") defer p.Exit() h := t.layout[v].height if e-s > h { e = s + h } else if e-s < h { s = e - h } if e2, _ := v.Buffer().RowCol(v.Buffer().TextPoint(e, 0)); e2 < e { e = e2 } if s < 0 { s = 0 } e = s + h r := Region{v.Buffer().TextPoint(s, 0), v.Buffer().TextPoint(e, 0)} return v.Buffer().LineR(r) }
func (t tbfe) setupCallbacks(view *backend.View) { // Ensure that the visible region currently presented is // inclusive of the insert/erase delta. view.Buffer().AddCallback(func(b Buffer, pos, delta int) { visible := t.layout[view].visible t.Show(view, Region{visible.Begin(), visible.End() + delta}) }) backend.OnNew.Add(func(v *backend.View) { v.Settings().AddOnChange("lime.frontend.termbox.render", func(name string) { t.render() }) }) backend.OnModified.Add(func(v *backend.View) { t.render() }) backend.OnSelectionModified.Add(func(v *backend.View) { t.render() }) }
func (t *tbfe) renderView(wr io.Writer, v *backend.View, lay layout) { p := util.Prof.Enter("render") defer p.Exit() vr := lay.visible runes := v.Buffer().Substr(vr) recipie := v.Transform(scheme, vr).Transcribe() highlight_line := false if b, ok := v.Settings().Get("highlight_line", highlight_line).(bool); ok { highlight_line = b } lastEnd := 0 for _, reg := range recipie { if lastEnd != reg.Region.Begin() { io.WriteString(wr, runes[lastEnd:reg.Region.Begin()]) } fmt.Fprintf(wr, "<span style=\"color:#%s; background-color:#%s\">%s</span>", htmlcol(reg.Flavour.Foreground), htmlcol(reg.Flavour.Background), runes[reg.Region.Begin():reg.Region.End()]) lastEnd = reg.Region.End() } if lastEnd != vr.End() { io.WriteString(wr, v.Buffer().Substr(Region{lastEnd, vr.End()})) } }
func (t *tbfe) Show(v *backend.View, r Region) { t.lock.Lock() l := t.layout[v] t.lock.Unlock() if l.visible.Covers(r) { return } p := util.Prof.Enter("show") defer p.Exit() lv := l.visible s1, _ := v.Buffer().RowCol(lv.Begin()) e1, _ := v.Buffer().RowCol(lv.End()) s2, _ := v.Buffer().RowCol(r.Begin()) e2, _ := v.Buffer().RowCol(r.End()) r1 := Region{s1, e1} r2 := Region{s2, e2} r3 := r1.Cover(r2) diff := 0 if d1, d2 := Abs(r1.Begin()-r3.Begin()), Abs(r1.End()-r3.End()); d1 > d2 { diff = r3.Begin() - r1.Begin() } else { diff = r3.End() - r1.End() } r3.A = r1.Begin() + diff r3.B = r1.End() + diff r3 = t.clip(v, r3.A, r3.B) l.visible = r3 t.lock.Lock() t.layout[v] = l t.lock.Unlock() t.render() }
func (t *tbfe) renderView(sx, sy, w, h int, v *backend.View) { sel := v.Sel() substr := v.Buffer().Data() vr := t.VisibleRegion(v) lines := strings.Split(substr, "\n") s, _ := v.Buffer().RowCol(vr.Begin()) e, _ := v.Buffer().RowCol(vr.End()) if e > 1 { e = e - 1 if e > h { s = e - h } } off := len(strings.Join(lines[:s], "\n")) lines = lines[s:e] runes := []rune(strings.Join(lines, "\n")) x, y := sx, sy ex, ey := sx+w, sy+h sub2 := "" var ( lastScope string lfg, lbg = defaultFg, defaultBg ) tab_size, ok := v.Settings().Get("tab_size", 4).(int) if !ok { tab_size = 4 } caret_style := termbox.AttrUnderline if b, ok := v.Settings().Get("caret_style", "underline").(string); ok { if b == "block" { caret_style = termbox.AttrReverse } } if b, ok := v.Settings().Get("inverse_caret_state", false).(bool); !b && ok { if caret_style == termbox.AttrReverse { caret_style = termbox.AttrUnderline } else { caret_style = termbox.AttrReverse } } caret_blink := true if b, ok := v.Settings().Get("caret_blink", true).(bool); ok { caret_blink = b } for i := range runes { sub2 += string(runes[i]) if x < ex { o := off + len(sub2) r := primitives.Region{o, o} fg, bg := lfg, lbg scope := v.ScopeName(o) if scope != lastScope { fg, bg = defaultFg, defaultBg lastScope = scope na := scope for len(na) > 0 { sn := na i := strings.LastIndex(sn, " ") if i != -1 { sn = sn[i+1:] } if c, ok := schemelut[sn]; ok { fg, bg = c[0], c[1] break } if i2 := strings.LastIndex(na, "."); i2 == -1 { break } else if i > i2 { na = na[:i] } else { na = strings.TrimSpace(na[:i2]) } } lfg, lbg = fg, bg } else { fg, bg = lfg, lbg } for _, r2 := range sel.Regions() { if r2.B == r.B { if !caret_blink || blink { if r2.Contains(o) { fg |= termbox.AttrReverse } else { fg |= caret_style } } break } else if r2.Contains(o) { fg |= termbox.AttrReverse break } } if runes[i] == '\t' { add := (x + 1 + (tab_size - 1)) &^ (tab_size - 1) for x < add { termbox.SetCell(x, y, ' ', fg, bg) x++ } continue } else if runes[i] == '\n' { termbox.SetCell(x, y, ' ', fg, bg) x = sx y++ if y > ey { break } continue } termbox.SetCell(x, y, runes[i], fg, bg) } x++ } }
func (t *tbfe) Show(v *backend.View, r primitives.Region) { t.visibleregion[v] = t.clip(v, primitives.Region{r.Begin(), v.Buffer().Size()}) }
func (t *tbfe) clip(v *backend.View, r primitives.Region) primitives.Region { s, _ := v.Buffer().RowCol(r.Begin()) e, _ := v.Buffer().RowCol(r.End()) _, h := termbox.Size() h -= console_height if e-s > h { e = s + h } if e2, _ := v.Buffer().RowCol(v.Buffer().TextPoint(e, 1)); e2 < e { e = e2 } if e-s < h { s = e - h } if s < 1 { s = 1 } r.A = v.Buffer().Line(v.Buffer().TextPoint(s, 1)).A r.B = v.Buffer().Line(v.Buffer().TextPoint(e, 1)).B return r }
func (t *tbfe) renderView(v *backend.View, lay layout) { p := util.Prof.Enter("render") defer p.Exit() sx, sy, w, h := lay.x, lay.y, lay.width, lay.height sel := v.Sel() vr := lay.visible runes := v.Buffer().SubstrR(vr) x, y := sx, sy ex, ey := sx+w, sy+h var ( lastScope string lfg, lbg = defaultFg, defaultBg ) tab_size, ok := v.Settings().Get("tab_size", 4).(int) if !ok { tab_size = 4 } caret_style := termbox.AttrUnderline if b, ok := v.Settings().Get("caret_style", "underline").(string); ok { if b == "block" { caret_style = termbox.AttrReverse } } if b, ok := v.Settings().Get("inverse_caret_state", false).(bool); !b && ok { if caret_style == termbox.AttrReverse { caret_style = termbox.AttrUnderline } else { caret_style = termbox.AttrReverse } } caret_blink := true if b, ok := v.Settings().Get("caret_blink", true).(bool); ok { caret_blink = b } highlight_line := false if b, ok := v.Settings().Get("highlight_line", highlight_line).(bool); ok { highlight_line = b } // TODO: much of this belongs in backend as it's not specific to any particular frontend for i := range runes { o := vr.Begin() + i fg, bg := lfg, lbg scope := v.ScopeName(o) var lr Region if highlight_line { lr = v.Buffer().Line(o) } if scope != lastScope { fg, bg = defaultFg, defaultBg lastScope = scope na := scope for len(na) > 0 { sn := na i := strings.LastIndex(sn, " ") if i != -1 { sn = sn[i+1:] } if c, ok := schemelut[sn]; ok { fg, bg = c[0], c[1] break } if i2 := strings.LastIndex(na, "."); i2 == -1 { break } else if i > i2 { na = na[:i] } else { na = strings.TrimSpace(na[:i2]) } } lfg, lbg = fg, bg } else { fg, bg = lfg, lbg } for _, r2 := range sel.Regions() { if highlight_line && (lr.Contains(r2.A) || lr.Contains(r2.B)) { // TODO: highlight color bg |= termbox.AttrReverse continue } if r2.Contains(o) { if r2.Size() == 0 { if !caret_blink || blink { fg |= caret_style } break } else if r2.Contains(o + 1) { // TODO: selection color fg |= termbox.AttrReverse break } } } if runes[i] == '\t' { add := (x + 1 + (tab_size - 1)) &^ (tab_size - 1) for x < add { if x < ex { termbox.SetCell(x, y, ' ', fg, bg) } fg = fg &^ termbox.AttrUnderline // Just looks weird with a long underline x++ } continue } else if runes[i] == '\n' { for ; x < ex; x++ { termbox.SetCell(x, y, ' ', fg, bg) if !highlight_line { break } } x = sx y++ if y > ey { break } continue } if x < ex { termbox.SetCell(x, y, runes[i], fg, bg) } x++ } }
func TestSublime(t *testing.T) { ed := backend.GetEditor() ed.Console().Buffer().AddCallback(func(b primitives.Buffer, pos, delta int) { t.Logf("%s", b.Substr(primitives.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 { scanpath("testdata/", 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) } og, err := py.Import("objgraph") if err != nil { log4go.Debug(err) return } gr, err := og.Dict().GetItemString("show_growth") if err != nil { log4go.Debug(err) return } log4go.Debug("Before") gr.Base().CallFunctionObjArgs() 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" { log4go.Debug("Running %s", fn) if _, err := py.Import(fn[:len(fn)-3]); err != nil { log4go.Error(err) t.Error(err) } else { log4go.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(primitives.Region{0, v.Buffer().Size()}), "FAILED") != -1 { t.Error(v.Buffer()) } } } log4go.Debug("After") l.Lock() gr.Base().CallFunctionObjArgs() l.Unlock() var v *backend.View for _, v2 := range w.Views() { if v == nil || v2.Buffer().Size() > v.Buffer().Size() { v = v2 } } // log4go.Debug("Before") // gr.Base().CallFunctionObjArgs() // for i := 0; i < 500; i++ { // ed.CommandHandler().RunTextCommand(v, "set_motion", backend.Args{"motion": "vi_j"}) // } // for i := 0; i < 500; i++ { // ed.CommandHandler().RunTextCommand(v, "set_motion", backend.Args{"motion": "vi_k"}) // } // log4go.Debug("After") // gr.Base().CallFunctionObjArgs() }
func (t *tbfe) renderView(v *backend.View, lay layout) { p := util.Prof.Enter("render") defer p.Exit() sx, sy, w, h := lay.x, lay.y, lay.width, lay.height vr := lay.visible runes := v.Buffer().Substr(vr) x, y := sx, sy ex, ey := sx+w, sy+h caretStyle := t.settings.caretStyle if t.settings.caretBlink && blink { t.settings.caretStyle = 0 } recipie := v.Transform(scheme, vr).Transcribe() fg, bg := defaultFg, defaultBg sel := v.Sel() line, _ := v.Buffer().RowCol(vr.Begin()) eofline, _ := v.Buffer().RowCol(v.Buffer().Size()) lineNumberRenderSize := len(intToRunes(eofline)) for i, r := range runes { o := vr.Begin() + i curr := 0 fg, bg = defaultFg, defaultBg if t.settings.lineNumbers { renderLineNumber(&line, &x, y, lineNumberRenderSize, fg, bg) } for curr < len(recipie) && (o >= recipie[curr].Region.Begin()) { if o < recipie[curr].Region.End() { fg = palLut(textmate.Color(recipie[curr].Flavour.Foreground)) bg = palLut(textmate.Color(recipie[curr].Flavour.Background)) } curr++ } if sel.Contains(Region{o, o}) { fg = fg | t.settings.caretStyle } if r == '\t' { add := (x + 1 + (t.settings.tabSize - 1)) &^ (t.settings.tabSize - 1) for x < add { if x < ex { termbox.SetCell(x, y, ' ', fg, bg) } fg = fg &^ termbox.AttrUnderline // Just looks weird with a long underline x++ } continue } else if r == '\n' { x = sx y++ if y > ey { break } continue } if x < ex { termbox.SetCell(x, y, r, fg, bg) } x++ } if t.settings.lineNumbers { renderLineNumber(&line, &x, y, lineNumberRenderSize, fg, bg) } // restore original caretStyle before blink modification t.settings.caretStyle = caretStyle }
func (t *tbfe) renderView(v *backend.View, lay layout) { p := util.Prof.Enter("render") defer p.Exit() sx, sy, w, h := lay.x, lay.y, lay.width, lay.height vr := lay.visible runes := v.Buffer().Substr(vr) x, y := sx, sy ex, ey := sx+w, sy+h tab_size, ok := v.Settings().Get("tab_size", 4).(int) if !ok { tab_size = 4 } recipie := v.Transform(scheme, vr).Transcribe() highlight_line := false if b, ok := v.Settings().Get("highlight_line", highlight_line).(bool); ok { highlight_line = b } if first && len(recipie) > 4 { first = false for i, v := range recipie { log4go.Debug("%d: %+v", i, v) } log4go.Debug("vr: %+v", vr) } // TODO: much of this belongs in backend as it's not specific to any particular frontend curr := 0 fg, bg := defaultFg, defaultBg _ = render.DRAW_TEXT for i, r := range runes { o := vr.Begin() + i curr = 0 fg, bg = defaultFg, defaultBg for curr < len(recipie) && (o >= recipie[curr].Region.Begin()) { // if curr > 0 { // curr-- // } if o < recipie[curr].Region.End() { fg = palLut(textmate.Color(recipie[curr].Flavour.Foreground)) bg = palLut(textmate.Color(recipie[curr].Flavour.Background)) } curr++ } if r == '\t' { add := (x + 1 + (tab_size - 1)) &^ (tab_size - 1) for x < add { if x < ex { termbox.SetCell(x, y, ' ', fg, bg) } // fg = fg &^ termbox.AttrUnderline // Just looks weird with a long underline x++ } continue } else if r == '\n' { // for ; x < ex; x++ { // termbox.SetCell(x, y, ' ', fg, bg) // if !highlight_line { // break // } // } x = sx y++ if y > ey { break } continue } if x < ex { termbox.SetCell(x, y, r, fg, bg) } x++ } }
func (t *tbfe) renderView(v *backend.View, lay layout) { p := util.Prof.Enter("render") defer p.Exit() sx, sy, w, h := lay.x, lay.y, lay.width, lay.height vr := lay.visible runes := v.Buffer().Substr(vr) x, y := sx, sy ex, ey := sx+w, sy+h tab_size, ok := v.Settings().Get("tab_size", 4).(int) if !ok { tab_size = 4 } recipie := v.Transform(scheme, vr).Transcribe() curr := 0 fg, bg := defaultFg, defaultBg _ = render.DRAW_TEXT sel := v.Sel() caret_blink := true if b, ok := v.Settings().Get("caret_blink", true).(bool); ok { caret_blink = b } highlight_line := false if b, ok := v.Settings().Get("highlight_line", highlight_line).(bool); ok { highlight_line = b } caret_style := termbox.AttrUnderline if b, ok := v.Settings().Get("caret_style", "underline").(string); ok { if b == "block" { caret_style = termbox.AttrReverse } } if b, ok := v.Settings().Get("inverse_caret_state", false).(bool); !b && ok { if caret_style == termbox.AttrReverse { caret_style = termbox.AttrUnderline } else { caret_style = termbox.AttrReverse } } if caret_blink && blink { caret_style = 0 } for i, r := range runes { o := vr.Begin() + i curr = 0 fg, bg = defaultFg, defaultBg for curr < len(recipie) && (o >= recipie[curr].Region.Begin()) { // if curr > 0 { // curr-- // } if o < recipie[curr].Region.End() { fg = palLut(textmate.Color(recipie[curr].Flavour.Foreground)) bg = palLut(textmate.Color(recipie[curr].Flavour.Background)) } curr++ } if sel.Contains(Region{o, o}) { fg = fg | caret_style } if r == '\t' { add := (x + 1 + (tab_size - 1)) &^ (tab_size - 1) for x < add { if x < ex { termbox.SetCell(x, y, ' ', fg, bg) } fg = fg &^ termbox.AttrUnderline // Just looks weird with a long underline x++ } continue } else if r == '\n' { // for ; x < ex; x++ { // termbox.SetCell(x, y, ' ', fg, bg) // if !highlight_line { // break // } // } x = sx y++ if y > ey { break } continue } if x < ex { termbox.SetCell(x, y, r, fg, bg) } x++ } }
func newQLimeView(v *backend.View) *QLimeView { log4go.Debug("new_QLimeView entered") defer log4go.Debug("new_QLimeView exited") var ret QLimeView ret.Widget = qt5.NewWidget() ret.v = v ret.Widget.OnPaintEvent(func(ev *qt5.PaintEvent) { p := qt5.NewPainter() defer p.Close() p.Begin(ret) b := v.Buffer() ps := p.Font().PointSize() pen := qt5.NewPen() p.SetPen(pen) brush := qt5.NewBrush() brush.SetStyle(qt5.SolidPattern) def := scheme.Settings[0] p.SetBrush(brush) f := p.Font() f.SetFixedPitch(true) p.SetFont(f) brush.SetColor(color.RGBA(def.Settings["background"])) p.DrawRect(ev.Rect()) is_widget, ok := v.Settings().Get("is_widget", false).(bool) is_widget = ok && is_widget pen.SetColor(color.RGBA(def.Settings["background"])) p.SetPen(pen) for y := 0; y < 20; y++ { pos := b.TextPoint(y, 0) line := b.Line(pos) if is_widget { p.DrawText(qt5.Point{0, (y + 1) * (ps + 2)}, b.Substr(line)) } else { for line.Contains(pos) { scope := primitives.Region{pos, pos} sn := v.ScopeName(pos) for line.Contains(pos) { pos++ if v.ScopeName(pos) != sn { scope.B = pos break } } is := line.Intersection(scope) c := color.RGBA(def.Settings["foreground"]) s := scheme.ClosestMatchingSetting(sn) if v, ok := s.Settings["foreground"]; ok { c = color.RGBA(v) } pen.SetColor(c) p.SetPen(pen) _, col := b.RowCol(line.A) p.DrawText(qt5.Point{col * ps / 2, (y + 1) * (ps + 2)}, b.Substr(is)) line.A = is.End() } } } }) ret.Widget.OnResizeEvent(func(ev *qt5.ResizeEvent) { if w, ok := v.Settings().Get("is_widget", false).(bool); ok && !w { ret.Widget.SetMinimumSize(qt5.Size{600, 100}) } }) v.Settings().Set("lime.qt.widget", &ret) return &ret }