Skip to content

Commit 4188666

Browse files
committed
First commit
0 parents  commit 4188666

File tree

11 files changed

+691
-0
lines changed

11 files changed

+691
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.png
2+
/.vscode/
3+
/gopherview

LICENSE.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# License
2+
3+
Copyright © 2018 OFTN Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to **view**,
7+
**use**, and/or **distribute** the Software, and to permit persons to whom the
8+
Software is furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software. **OFTN Inc. maintains exclusive
12+
rights to all other uses of the Software.**
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
SOFTWARE.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# GopherView
2+
3+
This project houses an in-progress Go debugger that turns your source code into
4+
a watchable movie.

codeview.go

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"go/scanner"
7+
"go/token"
8+
"image/color"
9+
"log"
10+
"strings"
11+
12+
"github.com/fogleman/gg"
13+
)
14+
15+
type CodeView struct {
16+
alloc *Allocation
17+
18+
// Information regarding the source code it contains
19+
fset *token.FileSet
20+
filename string
21+
source []byte
22+
sourceLines int
23+
sourceWidth int
24+
tokens []CodeViewToken
25+
26+
// Information regarding the typography
27+
fontFace string
28+
fontSize float64
29+
lineHeight float64
30+
}
31+
32+
type CodeViewToken struct {
33+
pos token.Pos
34+
tok token.Token
35+
lit string
36+
}
37+
38+
func (tok *CodeViewToken) Len() int {
39+
switch tok.tok {
40+
case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND,
41+
token.OR, token.XOR, token.LSS, token.GTR, token.ASSIGN, token.NOT,
42+
token.LPAREN, token.LBRACK, token.LBRACE, token.COMMA, token.PERIOD,
43+
token.RPAREN, token.RBRACK, token.RBRACE, token.SEMICOLON, token.COLON:
44+
// One-character operators
45+
return 1
46+
case token.SHL, token.SHR, token.AND_NOT, token.ADD_ASSIGN, token.SUB_ASSIGN,
47+
token.MUL_ASSIGN, token.QUO_ASSIGN, token.REM_ASSIGN, token.AND_ASSIGN,
48+
token.OR_ASSIGN, token.XOR_ASSIGN, token.LAND, token.LOR, token.ARROW,
49+
token.INC, token.DEC, token.EQL, token.NEQ, token.LEQ, token.GEQ,
50+
token.DEFINE:
51+
// Two-character operators
52+
return 2
53+
case token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN, token.ELLIPSIS:
54+
// Three-character operators
55+
return 3
56+
}
57+
return len(tok.lit)
58+
}
59+
60+
func NewCodeView(filename string, source []byte) *CodeView {
61+
codeview := &CodeView{
62+
filename: filename,
63+
source: source,
64+
65+
fontFace: "/usr/share/fonts/TTF/DejaVuSansMono.ttf",
66+
fontSize: 16,
67+
lineHeight: 24,
68+
}
69+
70+
// Get line count
71+
72+
lines := bytes.Split(source, []byte("\n"))
73+
for line := range lines {
74+
width := len(lines[line])
75+
if width > codeview.sourceWidth {
76+
codeview.sourceWidth = width
77+
}
78+
codeview.sourceLines++
79+
}
80+
81+
// Tokenize
82+
83+
codeview.fset = token.NewFileSet()
84+
scan := scanner.Scanner{}
85+
86+
file := codeview.fset.AddFile(filename, codeview.fset.Base(), len(source))
87+
scan.Init(file, source, nil, scanner.ScanComments)
88+
89+
for {
90+
pos, tok, lit := scan.Scan()
91+
if tok == token.EOF {
92+
break
93+
}
94+
95+
codeview.tokens = append(codeview.tokens, CodeViewToken{pos, tok, lit})
96+
}
97+
98+
return codeview
99+
}
100+
101+
func (c *CodeView) Render(context *gg.Context) {
102+
alloc := c.Allocation()
103+
104+
context.SetColor(PaperColorScheme.Back)
105+
context.DrawRectangle(0, 0, alloc.Width, alloc.Height)
106+
context.FillPreserve()
107+
context.Clip()
108+
defer context.ResetClip()
109+
110+
context.SetColor(PaperColorScheme.Text)
111+
if err := context.LoadFontFace(c.fontFace, c.fontSize); err != nil {
112+
log.Print(err)
113+
return
114+
}
115+
116+
lineY := c.lineHeight / 2
117+
lines := bytes.Split(c.source, []byte("\n"))
118+
currentTokIndex := 0
119+
120+
for lineIndex, line := range lines {
121+
// Keep track of the indices to change colors
122+
type ColorMarker struct {
123+
Index int
124+
Color color.Color
125+
}
126+
fmt.Printf("\nline %d of %d: %s\n", lineIndex+1, len(lines), line)
127+
128+
// Add all tokens from this line
129+
markers := []ColorMarker{{0, PaperColorScheme.Text}}
130+
for currentTokIndex < len(c.tokens) {
131+
tok := c.tokens[currentTokIndex]
132+
pos := c.fset.Position(tok.pos)
133+
if pos.Line != lineIndex+1 {
134+
// There are no more tokens on this line
135+
break
136+
}
137+
indexStart := pos.Column - 1
138+
indexEnd := indexStart + tok.Len()
139+
if indexEnd > len(line) {
140+
indexEnd = len(line)
141+
}
142+
fmt.Printf("adding token %q %q index %d:%d\n", tok.tok, tok.lit, indexStart, indexEnd)
143+
markers = append(markers,
144+
ColorMarker{indexStart, PaperColorScheme.Tokens[tok.tok]},
145+
ColorMarker{indexEnd, PaperColorScheme.Text})
146+
currentTokIndex++
147+
}
148+
markers = append(markers, ColorMarker{len(line), PaperColorScheme.Text})
149+
150+
// Iterate each consecutive pair of markers that has text in between
151+
var lineX float64
152+
for index := 0; index < len(markers)-1; index++ {
153+
markerA, markerB := markers[index], markers[index+1]
154+
if markerA.Index == markerB.Index {
155+
continue
156+
}
157+
str := string(line[markerA.Index:markerB.Index])
158+
str = strings.Replace(str, "\t", " ", -1)
159+
160+
width, _ := context.MeasureString(str)
161+
context.SetColor(markerA.Color)
162+
context.DrawStringAnchored(str, lineX, lineY, 0, 0.5)
163+
164+
lineX += width
165+
}
166+
lineY += c.lineHeight
167+
}
168+
context.Fill()
169+
}
170+
171+
func (c *CodeView) Measure(orient Orientation, forsize float64) (minimum, natural float64) {
172+
switch orient {
173+
case Horizontal:
174+
// Natural and minimum size is the width of the longest line
175+
minimum = float64(c.sourceWidth) * c.fontSize
176+
natural = minimum
177+
178+
case Vertical:
179+
// Natural size is the number of lines times the line height
180+
// Minimum size is 3 lines
181+
minimum = 3 * c.lineHeight
182+
natural = float64(c.sourceLines) * c.lineHeight
183+
}
184+
return
185+
}
186+
187+
func (c *CodeView) Allocate(alloc *Allocation) {
188+
c.alloc = alloc
189+
}
190+
191+
func (c *CodeView) Allocation() Allocation {
192+
return *c.alloc
193+
}

goghlang

3.14 MB
Binary file not shown.

layout.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package main
2+
3+
import "github.com/fogleman/gg"
4+
5+
type Layout struct {
6+
View
7+
8+
Children []View
9+
alloc *Allocation
10+
}
11+
12+
func (c *Layout) Add(child View) {
13+
c.Children = append(c.Children, child)
14+
}
15+
16+
func (c *Layout) Remove(child View) {
17+
list := c.Children[:0]
18+
for _, item := range c.Children {
19+
if item != child {
20+
list = append(list, item)
21+
}
22+
}
23+
c.Children = list
24+
}
25+
26+
func (c *Layout) Render(context *gg.Context) {
27+
context.Push()
28+
defer context.Pop()
29+
30+
// FIXME: https://github.com/fogleman/gg/issues/27
31+
// alloc := c.Allocation()
32+
// context.DrawRectangle(alloc.X, alloc.Y, alloc.Width, alloc.Height)
33+
// context.Clip()
34+
// defer context.ResetClip()
35+
36+
for _, child := range c.Children {
37+
func() {
38+
context.Push()
39+
defer context.Pop()
40+
41+
alloc := child.Allocation()
42+
context.Translate(alloc.X, alloc.Y)
43+
child.Render(context)
44+
}()
45+
}
46+
}
47+
48+
func (c *Layout) Allocation() Allocation {
49+
return *c.alloc
50+
}
51+
52+
func (c *Layout) Len() int {
53+
return len(c.Children)
54+
}

0 commit comments

Comments
 (0)