-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathformat.go
More file actions
99 lines (90 loc) · 2.91 KB
/
Copy pathformat.go
File metadata and controls
99 lines (90 loc) · 2.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package main
import (
"bytes"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"sort"
"strings"
)
// Fixes the imports of p.TempFile and formats the file
func (p *Program) fixFile(executingFragment int) error {
// Find GOPATH
gopath, err := exec.Command("go", "env", "GOPATH", filepath.Join(p.TempFile)).CombinedOutput()
gopls := strings.ReplaceAll(string(gopath), "\n", "") + "/bin/gopls"
if err != nil {
return err
}
// Adds package imports and removes anything unused
err = exec.Command(gopls, "imports", "-w", filepath.Join(p.TempFile)).Run()
if err != nil {
return err
}
go p.formatFile()
return nil
}
// Format the temp file, as some users will check the source code
// Runs in a separate go routine as not required before returning output
func (p *Program) formatFile() {
err := exec.Command("go", "fmt", filepath.Join(p.TempFile)).Run()
if err != nil {
log.Println(err)
}
}
// Determines what order the file should be written based on existing
// execution order (fragments) and new execution order (index)
// Fragment is a VS Code notebook term that identifies a cell at the time
// of execution, so if it changes order we can still modify the same cell
func (p *Program) writeFile(input Cell) error {
// Overwrites cell if it already existed
p.Cells[input.Fragment] = &input
// The keys are used to determine current order of the notebook cells
// The fragments are the original order
keys := []FragmentKey{}
for _, v := range p.Cells {
keys = append(keys, []int{v.Index, v.Fragment})
}
// Sort keys by the new order
sort.Slice(keys, func(i, j int) bool {
if keys[i][0] == keys[j][0] {
return true
}
return keys[i][0] < keys[j][0]
})
// Two buffers, one for code going in main and one for everything else
var programBuf bytes.Buffer
var mainFuncBuf bytes.Buffer
for _, key := range keys {
c := p.Cells[key[1]]
// If cell contains a function or type, don't write cell to mainBuf
reType, _ := regexp.Compile(`\s*type\s+\w+\s+.*`)
reFunc, _ := regexp.Compile(`\s*func\s+\w+\s*\(.*\).*{`)
reRecFunc, _ := regexp.Compile(`\s*func \(.*\)\s+\w+\(.*\).*{`)
if reFunc.MatchString(c.Contents) || reType.MatchString(c.Contents) || reRecFunc.MatchString(c.Contents) {
// Add it instead to the functions string
p.Functions += "\n" + c.Contents
// Also stop any output returning to to client
c.Executing = false
} else {
if c.Executing {
// This output is used to limit returned text to the executing cell
fmt.Fprint(&mainFuncBuf, `println("gobook-output-start")`)
}
fmt.Fprint(&mainFuncBuf, "\n"+c.Contents+"\n")
if c.Executing {
fmt.Fprint(&mainFuncBuf, `println("gobook-output-end") `)
}
}
}
p.Cells[input.Fragment].Executing = false
// Write the program
fmt.Fprintf(&programBuf, ("package main\n\n%s\n\nfunc main() {%s\n}"), p.Functions, &mainFuncBuf)
err := os.WriteFile(p.TempFile, programBuf.Bytes(), 0600)
if err != nil {
return err
}
return nil
}