This commit is contained in:
Liang Ding 2014-10-29 00:37:47 +08:00
parent 542bf019a3
commit ee52e46b8a
1 changed files with 44 additions and 37 deletions

View File

@ -28,17 +28,18 @@ type FileNode struct {
FileNodes []*FileNode `json:"children"` FileNodes []*FileNode `json:"children"`
} }
// 代码片段. 这个结构可用于“查找使用”、“文件搜索”等的返回值. // Source code snippet, used to as the result of "Find Usages", "Search".
type Snippet struct { type Snippet struct {
Path string `json:"path"` // 文件路径 Path string `json:"path"` // file path
Line int `json:"line"` // 行号 Line int `json:"line"` // line number
Ch int `json:"ch"` // 列号 Ch int `json:"ch"` // column number
Contents []string `json:"contents"` // 附近几行 Contents []string `json:"contents"` // lines nearby
} }
// 构造用户工作空间文件树. // GetFiles handles request of constructing user workspace file tree.
// //
// 将 Go API 源码包($GOROOT/src/pkg也作为子节点这样能方便用户查看 Go API 源码. // The Go API source code package ($GOROOT/src/pkg) also as a child node,
// so that users can easily view the Go API source code.
func GetFiles(w http.ResponseWriter, r *http.Request) { func GetFiles(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{"succ": true} data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data) defer util.RetJSON(w, r, data)
@ -51,7 +52,7 @@ func GetFiles(w http.ResponseWriter, r *http.Request) {
root := FileNode{Name: "root", Path: "", IconSkin: "ico-ztree-dir ", Type: "d", FileNodes: []*FileNode{}} root := FileNode{Name: "root", Path: "", IconSkin: "ico-ztree-dir ", Type: "d", FileNodes: []*FileNode{}}
// 工作空间节点处理 // workspace node process
for _, workspace := range workspaces { for _, workspace := range workspaces {
workspacePath := workspace + conf.PathSeparator + "src" workspacePath := workspace + conf.PathSeparator + "src"
@ -61,36 +62,36 @@ func GetFiles(w http.ResponseWriter, r *http.Request) {
walk(workspacePath, &workspaceNode) walk(workspacePath, &workspaceNode)
// 添加工作空间节点 // add workspace node
root.FileNodes = append(root.FileNodes, &workspaceNode) root.FileNodes = append(root.FileNodes, &workspaceNode)
} }
// 构造 Go API 节点 // construct Go API node
apiPath := runtime.GOROOT() + conf.PathSeparator + "src" + conf.PathSeparator + "pkg" apiPath := runtime.GOROOT() + conf.PathSeparator + "src" + conf.PathSeparator + "pkg"
apiNode := FileNode{Name: "Go API", Path: apiPath, FileNodes: []*FileNode{}} apiNode := FileNode{Name: "Go API", Path: apiPath, FileNodes: []*FileNode{}}
goapiBuildOKSignal := make(chan bool) goapiBuildOKSignal := make(chan bool)
go func() { go func() {
apiNode.Type = "d" apiNode.Type = "d"
// TOOD: Go API 用另外的样式 // TOOD: Go API use a special style
apiNode.IconSkin = "ico-ztree-dir " apiNode.IconSkin = "ico-ztree-dir "
walk(apiPath, &apiNode) walk(apiPath, &apiNode)
// 放行信号 // go-ahead
close(goapiBuildOKSignal) close(goapiBuildOKSignal)
}() }()
// 等待放行 // waiting
<-goapiBuildOKSignal <-goapiBuildOKSignal
// 添加 Go API 节点 // add Go API node
root.FileNodes = append(root.FileNodes, &apiNode) root.FileNodes = append(root.FileNodes, &apiNode)
data["root"] = root data["root"] = root
} }
// 编辑器打开一个文件. // GetFile handles request of opening file by editor.
func GetFile(w http.ResponseWriter, r *http.Request) { func GetFile(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{"succ": true} data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data) defer util.RetJSON(w, r, data)
@ -109,8 +110,9 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
extension := filepath.Ext(path) extension := filepath.Ext(path)
// 通过文件扩展名判断是否是图片文件(图片在浏览器里新建 tab 打开)
if isImg(extension) { if isImg(extension) {
// image file will be open in a browser tab
data["mode"] = "img" data["mode"] = "img"
path2 := strings.Replace(path, "\\", "/", -1) path2 := strings.Replace(path, "\\", "/", -1)
@ -121,15 +123,14 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
} }
isBinary := false isBinary := false
// 判断是否是其他二进制文件 // determine whether it is a binary file
for _, b := range buf { for _, b := range buf {
if 0 == b { // 包含 0 字节就认为是二进制文件 if 0 == b {
isBinary = true isBinary = true
} }
} }
if isBinary { if isBinary {
// 是二进制文件的话前端编辑器不打开
data["succ"] = false data["succ"] = false
data["msg"] = "Can't open a binary file :(" data["msg"] = "Can't open a binary file :("
} else { } else {
@ -139,7 +140,7 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
} }
} }
// 保存文件. // SaveFile handles request of saving file.
func SaveFile(w http.ResponseWriter, r *http.Request) { func SaveFile(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{"succ": true} data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data) defer util.RetJSON(w, r, data)
@ -172,6 +173,9 @@ func SaveFile(w http.ResponseWriter, r *http.Request) {
glog.Error(err) glog.Error(err)
data["succ"] = false data["succ"] = false
wSession.EventQueue.Queue <- &event.Event{Code: event.EvtCodeServerInternalError, Sid: sid,
Data: "can't save file " + filePath}
return return
} }
} }
@ -229,6 +233,9 @@ func RemoveFile(w http.ResponseWriter, r *http.Request) {
if !removeFile(path) { if !removeFile(path) {
data["succ"] = false data["succ"] = false
wSession.EventQueue.Queue <- &event.Event{Code: event.EvtCodeServerInternalError, Sid: sid,
Data: "can't remove file " + path}
} }
} }
@ -255,7 +262,7 @@ func SearchText(w http.ResponseWriter, r *http.Request) {
data["founds"] = founds data["founds"] = founds
} }
// 遍历指定的路径,构造文件树. // walk traverses the specified path to build a file tree.
func walk(path string, node *FileNode) { func walk(path string, node *FileNode) {
files := listFiles(path) files := listFiles(path)
@ -290,7 +297,7 @@ func walk(path string, node *FileNode) {
return return
} }
// 列出 dirname 指定目录下的文件/目录名. // listFiles lists names of files under the specified dirname.
func listFiles(dirname string) []string { func listFiles(dirname string) []string {
f, _ := os.Open(dirname) f, _ := os.Open(dirname)
@ -302,12 +309,12 @@ func listFiles(dirname string) []string {
dirs := []string{} dirs := []string{}
files := []string{} files := []string{}
// 排序:目录靠前,文件靠后 // sort: directories in front of files
for _, name := range names { for _, name := range names {
fio, _ := os.Lstat(filepath.Join(dirname, name)) fio, _ := os.Lstat(filepath.Join(dirname, name))
if fio.IsDir() { if fio.IsDir() {
// 排除 .git 目录 // exclude the .git direcitory
if ".git" == fio.Name() { if ".git" == fio.Name() {
continue continue
} }
@ -321,9 +328,9 @@ func listFiles(dirname string) []string {
return append(dirs, files...) return append(dirs, files...)
} }
// 根据文件后缀获取文件树图标 CSS 类名. // getIconSkin gets CSS class name of icon with the specified filename extension.
// //
// CSS 类名可参考 zTree 文档. // Refers to the zTree document for CSS class names.
func getIconSkin(filenameExtension string) string { func getIconSkin(filenameExtension string) string {
if isImg(filenameExtension) { if isImg(filenameExtension) {
return "ico-ztree-img " return "ico-ztree-img "
@ -353,9 +360,9 @@ func getIconSkin(filenameExtension string) string {
} }
} }
// 根据文件后缀获取编辑器 mode. // getEditorMode gets editor mode with the specified filename extension.
// //
// 编辑器 mode 可参考 CodeMirror 文档. // Refers to the CodeMirror document for modes.
func getEditorMode(filenameExtension string) string { func getEditorMode(filenameExtension string) string {
switch filenameExtension { switch filenameExtension {
case ".go": case ".go":
@ -381,12 +388,12 @@ func getEditorMode(filenameExtension string) string {
} }
} }
// 在 path 指定的路径上创建文件. // createFile creates file on the specified path.
// //
// fileType: // fileType:
// //
// "f": 文件 // "f": file
// "d": 目录 // "d": directory
func createFile(path, fileType string) bool { func createFile(path, fileType string) bool {
switch fileType { switch fileType {
case "f": case "f":
@ -421,7 +428,7 @@ func createFile(path, fileType string) bool {
} }
} }
// 删除 path 指定路径的文件或目录. // removeFile removes file on the specified path.
func removeFile(path string) bool { func removeFile(path string) bool {
if err := os.RemoveAll(path); nil != err { if err := os.RemoveAll(path); nil != err {
glog.Errorf("Removes [%s] failed: [%s]", path, err.Error()) glog.Errorf("Removes [%s] failed: [%s]", path, err.Error())
@ -434,7 +441,7 @@ func removeFile(path string) bool {
return true return true
} }
// 在 dir 指定的目录(包含子目录)中的 extension 指定后缀的文件中搜索包含 text 文本的文件,类似 grep/findstr 命令. // search finds file under the specified dir and its sub-directories with the specified text, likes the command grep/findstr.
func search(dir, extension, text string, snippets []*Snippet) []*Snippet { func search(dir, extension, text string, snippets []*Snippet) []*Snippet {
if !strings.HasSuffix(dir, conf.PathSeparator) { if !strings.HasSuffix(dir, conf.PathSeparator) {
dir += conf.PathSeparator dir += conf.PathSeparator
@ -454,10 +461,10 @@ func search(dir, extension, text string, snippets []*Snippet) []*Snippet {
path := dir + fileInfo.Name() path := dir + fileInfo.Name()
if fileInfo.IsDir() { if fileInfo.IsDir() {
// 进入目录递归 // enter the directory recursively
snippets = search(path, extension, text, snippets) snippets = search(path, extension, text, snippets)
} else if strings.HasSuffix(path, extension) { } else if strings.HasSuffix(path, extension) {
// 在文件中进行搜索 // grep in file
ss := searchInFile(path, text) ss := searchInFile(path, text)
snippets = append(snippets, ss...) snippets = append(snippets, ss...)
@ -467,7 +474,7 @@ func search(dir, extension, text string, snippets []*Snippet) []*Snippet {
return snippets return snippets
} }
// 在 path 指定的文件内容中搜索 text 指定的文本. // searchInFile finds file with the specified path and text.
func searchInFile(path string, text string) []*Snippet { func searchInFile(path string, text string) []*Snippet {
ret := []*Snippet{} ret := []*Snippet{}
@ -494,7 +501,7 @@ func searchInFile(path string, text string) []*Snippet {
return ret return ret
} }
// 根据文件名后缀判断是否是图片文件. // isImg determines whether the specified extension is a image.
func isImg(extension string) bool { func isImg(extension string) bool {
ext := strings.ToLower(extension) ext := strings.ToLower(extension)