fork of https://github.com/sourcegraph/zoekt
0

Configure Feed

Select the types of activity you want to include in your feed.

Support for --_interactive mode of universal-ctags.

For running the tests, a universal-ctags version of
5d82ee6e92ee9cdda5cc9dcee91646dd678b4b42 or newer is needed.

Change-Id: I9aa13237d1045e5169a49bd76aab9a398c4a0c36

+256 -4
+161
ctags/json.go
··· 1 + // Copyright 2017 Google Inc. All rights reserved. 2 + // 3 + // Licensed under the Apache License, Version 2.0 (the "License"); 4 + // you may not use this file except in compliance with the License. 5 + // You may obtain a copy of the License at 6 + // 7 + // http://www.apache.org/licenses/LICENSE-2.0 8 + // 9 + // Unless required by applicable law or agreed to in writing, software 10 + // distributed under the License is distributed on an "AS IS" BASIS, 11 + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 + // See the License for the specific language governing permissions and 13 + // limitations under the License. 14 + 15 + package ctags 16 + 17 + import ( 18 + "bufio" 19 + "encoding/json" 20 + "io" 21 + "os" 22 + "os/exec" 23 + "runtime" 24 + "sync" 25 + ) 26 + 27 + type ctagsProcess struct { 28 + cmd *exec.Cmd 29 + in io.WriteCloser 30 + out *bufio.Scanner 31 + outPipe io.ReadCloser 32 + 33 + procErrMu sync.Mutex 34 + procErr error 35 + } 36 + 37 + var bin = "universal-ctags" 38 + 39 + func newProcess() (*ctagsProcess, error) { 40 + opt := "default" 41 + if runtime.GOOS == "linux" { 42 + opt = "sandbox" 43 + } 44 + 45 + cmd := exec.Command(bin, "--_interactive="+opt, "--fields=*") 46 + in, err := cmd.StdinPipe() 47 + if err != nil { 48 + return nil, err 49 + } 50 + 51 + out, err := cmd.StdoutPipe() 52 + if err != nil { 53 + in.Close() 54 + return nil, err 55 + } 56 + cmd.Stderr = os.Stderr 57 + proc := ctagsProcess{ 58 + cmd: cmd, 59 + in: in, 60 + out: bufio.NewScanner(out), 61 + outPipe: out, 62 + } 63 + 64 + if err := cmd.Start(); err != nil { 65 + return nil, err 66 + } 67 + 68 + var init reply 69 + if err := proc.read(&init); err != nil { 70 + return nil, err 71 + } 72 + 73 + return &proc, nil 74 + } 75 + 76 + func (p *ctagsProcess) Close() { 77 + p.cmd.Process.Kill() 78 + p.outPipe.Close() 79 + p.in.Close() 80 + } 81 + 82 + func (p *ctagsProcess) read(rep *reply) error { 83 + if !p.out.Scan() { 84 + // capture exit error. 85 + err := p.cmd.Wait() 86 + p.outPipe.Close() 87 + p.in.Close() 88 + return err 89 + } 90 + return json.Unmarshal(p.out.Bytes(), rep) 91 + } 92 + 93 + func (p *ctagsProcess) post(req *request, content []byte) error { 94 + body, err := json.Marshal(req) 95 + if err != nil { 96 + return err 97 + } 98 + body = append(body, '\n') 99 + if _, err = p.in.Write(body); err != nil { 100 + return err 101 + } 102 + _, err = p.in.Write(content) 103 + 104 + return err 105 + } 106 + 107 + type request struct { 108 + Command string `json:"command"` 109 + Filename string `json:"filename"` 110 + Size int `json:"size"` 111 + } 112 + 113 + type reply struct { 114 + // Init 115 + Typ string `json:"_type"` 116 + Name string `json:"name"` 117 + Version string `json:"version"` 118 + 119 + // completed 120 + Command string `json:"command"` 121 + 122 + Path string `json:"path"` 123 + Pattern string `json:"pattern"` 124 + Language string `json:"language"` 125 + Line int `json:"line"` 126 + Kind string `json:"kind"` 127 + } 128 + 129 + func (p *ctagsProcess) Process(name string, content []byte) ([]*Entry, error) { 130 + req := request{ 131 + Command: "generate-tags", 132 + Size: len(content), 133 + Filename: name, 134 + } 135 + 136 + if err := p.post(&req, content); err != nil { 137 + return nil, err 138 + } 139 + 140 + var es []*Entry 141 + for { 142 + var rep reply 143 + if err := p.read(&rep); err != nil { 144 + return nil, err 145 + } 146 + if rep.Typ == "completed" { 147 + break 148 + } 149 + 150 + e := Entry{ 151 + Sym: rep.Name, 152 + Path: rep.Path, 153 + Line: rep.Line, 154 + Kind: rep.Kind, 155 + } 156 + 157 + es = append(es, &e) 158 + } 159 + 160 + return es, nil 161 + }
+94
ctags/json_test.go
··· 1 + // Copyright 2017 Google Inc. All rights reserved. 2 + // 3 + // Licensed under the Apache License, Version 2.0 (the "License"); 4 + // you may not use this file except in compliance with the License. 5 + // You may obtain a copy of the License at 6 + // 7 + // http://www.apache.org/licenses/LICENSE-2.0 8 + // 9 + // Unless required by applicable law or agreed to in writing, software 10 + // distributed under the License is distributed on an "AS IS" BASIS, 11 + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 + // See the License for the specific language governing permissions and 13 + // limitations under the License. 14 + 15 + package ctags 16 + 17 + import ( 18 + "reflect" 19 + "testing" 20 + ) 21 + 22 + func TestJSON(t *testing.T) { 23 + p, err := newProcess() 24 + if err != nil { 25 + t.Fatal("newProcess", err) 26 + } 27 + 28 + defer p.Close() 29 + 30 + java := ` 31 + package io.zoekt; 32 + import java.util.concurrent.Future; 33 + class Back implements Future extends Frob { 34 + public static int BLA = 1; 35 + public int member; 36 + public Back() { 37 + member = 2; 38 + } 39 + public int method() { 40 + member++; 41 + } 42 + } 43 + ` 44 + name := "io/zoekt/Back.java" 45 + got, err := p.Process(name, []byte(java)) 46 + if err != nil { 47 + t.Errorf("Process: %v", err) 48 + } 49 + 50 + want := []*Entry{ 51 + { 52 + Sym: "io.zoekt", 53 + Kind: "package", 54 + Path: "io/zoekt/Back.java", 55 + Line: 2, 56 + }, 57 + { 58 + Sym: "Back", 59 + Path: "io/zoekt/Back.java", 60 + Line: 4, 61 + Kind: "class", 62 + }, 63 + 64 + { 65 + Sym: "BLA", 66 + Path: "io/zoekt/Back.java", 67 + Line: 5, 68 + Kind: "field", 69 + }, 70 + { 71 + Sym: "member", 72 + Path: "io/zoekt/Back.java", 73 + Line: 6, 74 + Kind: "field", 75 + }, 76 + { 77 + Sym: "Back", 78 + Path: "io/zoekt/Back.java", 79 + Line: 7, 80 + Kind: "method", 81 + }, 82 + { 83 + Sym: "method", 84 + Path: "io/zoekt/Back.java", 85 + Line: 10, Kind: "method", 86 + }, 87 + } 88 + 89 + for i := range want { 90 + if !reflect.DeepEqual(got[i], want[i]) { 91 + t.Fatalf("got %#v, want %#v", got[i], want[i]) 92 + } 93 + } 94 + }
+1 -4
ctags/parse.go
··· 28 28 Parent string 29 29 ParentType string 30 30 31 - FileLimited bool 32 - Access string 33 - Implementation bool 34 - Inherits []string 31 + FileLimited bool 35 32 } 36 33 37 34 // Parse parses a single line of exuberant "ctags -n" output.