[gnome-code-assistance] [backends/go] Fix for new architecture



commit 9cda0d97c416a8c9e0547b6c36bf04673596d900
Author: Jesse van den Kieboom <jessevdk gmail com>
Date:   Mon Nov 11 14:56:17 2013 +0100

    [backends/go] Fix for new architecture

 backends/go/app.go             |   56 ---------
 backends/go/dbus.go            |  108 ++++++++++++++++
 backends/go/diagnostic.go      |   57 ---------
 backends/go/diagnostic_dbus.go |   35 -----
 backends/go/document.go        |   36 ------
 backends/go/document_dbus.go   |   45 -------
 backends/go/server_dbus.go     |  268 ++++++++++++++++++++++++++++++++++++++++
 backends/go/service.go         |  103 ++++++++++++++--
 backends/go/service_dbus.go    |  237 -----------------------------------
 backends/go/transport_dbus.go  |   23 +++-
 10 files changed, 487 insertions(+), 481 deletions(-)
---
diff --git a/backends/go/dbus.go b/backends/go/dbus.go
new file mode 100644
index 0000000..c5d429d
--- /dev/null
+++ b/backends/go/dbus.go
@@ -0,0 +1,108 @@
+package main
+
+import (
+       "github.com/guelfey/go.dbus"
+       "github.com/guelfey/go.dbus/introspect"
+)
+
+type ServiceDbus struct {
+       Server *ServerDbus
+}
+
+type DocumentDbus struct {
+       Document *Document
+}
+
+type OpenDocument struct {
+       Path     string
+       DataPath string
+}
+
+type RemoteDocument struct {
+       Path       string
+       ObjectPath dbus.ObjectPath
+}
+
+func (s *ServiceDbus) Introspect() *introspect.Node {
+       n := &introspect.Node{
+               Interfaces: []introspect.Interface{
+                       {
+                               Name:    "org.gnome.CodeAssist.Service",
+                               Methods: []introspect.Method{
+                                       {
+                                               Name: "Parse",
+                                               Args: []introspect.Arg{
+                                                       {"path", "s", "in"},
+                                                       {"cursor", "x", "in"},
+                                                       {"data_path", "s", "in"},
+                                                       {"options", "a{sv}", "in"},
+                                                       {"result", "o", "out"},
+                                               },
+                                       },
+                                       {
+                                               Name: "Dispose",
+                                               Args: []introspect.Arg{
+                                                       {"path", "s", "in"},
+                                               },
+                                       },
+                               },
+                       },
+
+                       introspect.Interface{
+                               Name:    "org.gnome.CodeAssist.Project",
+                               Methods: []introspect.Method{
+                                       {
+                                               Name: "ParseAll",
+                                               Args: []introspect.Arg{
+                                                       {"path", "s", "in"},
+                                                       {"cursor", "x", "in"},
+                                                       {"documents", "a(ss)", "in"},
+                                                       {"options", "a{sv}", "in"},
+                                                       {"result", "a(so)", "out"},
+                                               },
+                                       },
+                               },
+                       },
+               },
+       }
+
+       return n
+}
+
+func (d *DocumentDbus) Introspect() *introspect.Node {
+       return &introspect.Node{
+               Interfaces: []introspect.Interface{
+                       introspect.Interface{
+                               Name:    "org.gnome.CodeAssist.Document",
+                       },
+
+                       introspect.Interface{
+                               Name:    "org.gnome.CodeAssist.Diagnostics",
+                               Methods: []introspect.Method{
+                                       {
+                                               Name: "Diagnostics",
+                                               Args: []introspect.Arg{
+                                                       {"result", "a(ua((x(xx)(xx))s)a(x(xx)(xx))s)", "out"},
+                                               },
+                                       },
+                               },
+                       },
+               },
+       }
+}
+
+func (s *ServiceDbus) Parse(path string, cursor int64, dataPath string, options map[string]dbus.Variant, 
sender dbus.Sender) (dbus.ObjectPath, *dbus.Error) {
+       return s.Server.Parse(string(sender), path, cursor, dataPath, options)
+}
+
+func (s *ServiceDbus) Dispose(path string, sender dbus.Sender) *dbus.Error {
+       return s.Server.Dispose(string(sender), path)
+}
+
+func (s *ServiceDbus) ParseAll(path string, cursor int64, documents []OpenDocument, options 
map[string]dbus.Variant, sender dbus.Sender) ([]RemoteDocument, *dbus.Error) {
+       return s.Server.ParseAll(string(sender), path, cursor, documents, options)
+}
+
+func (d *DocumentDbus) Diagnostics() ([]Diagnostic, *dbus.Error) {
+       return d.Document.Diagnostics, nil
+}
diff --git a/backends/go/server_dbus.go b/backends/go/server_dbus.go
new file mode 100644
index 0000000..00624d0
--- /dev/null
+++ b/backends/go/server_dbus.go
@@ -0,0 +1,268 @@
+package main
+
+import (
+       "fmt"
+       "github.com/guelfey/go.dbus"
+       "os"
+       "path/filepath"
+       "sync"
+)
+
+type App struct {
+       id   uint64
+       name string
+
+       docs   map[string]*DocumentDbus
+
+       service *Service
+
+       nextid uint64
+       mutex  sync.Mutex
+}
+
+type ServerDbus struct {
+       transport *TransportDbus
+       service   *ServiceDbus
+       apps      map[string]*App
+       nextid    uint64
+       mutex     sync.Mutex
+}
+
+func NewServerDbus(transport *TransportDbus) (*ServerDbus, error) {
+       ret := &ServerDbus{
+               transport: transport,
+               apps:      make(map[string]*App),
+       }
+
+       ret.service = &ServiceDbus{
+               Server: ret,
+       }
+
+       transport.export(ret.service, ret.dbusPath())
+       transport.export(new(DocumentDbus), dbus.ObjectPath(fmt.Sprintf("%s/document", ret.dbusPath())))
+
+       go func() {
+               c := make(chan *dbus.Signal, 30)
+               transport.conn.Signal(c)
+
+               for v := range c {
+                       if len(v.Body) != 3 {
+                               continue
+                       }
+
+                       oldname := v.Body[1].(string)
+                       newname := v.Body[2].(string)
+
+                       if len(newname) != 0 {
+                               continue
+                       }
+
+                       ret.mutex.Lock()
+                       defer ret.mutex.Unlock()
+
+                       if app := ret.apps[oldname]; app != nil {
+                               app.mutex.Lock()
+                               defer app.mutex.Unlock()
+
+                               ret.disposeApp(app)
+                       }
+               }
+       }()
+
+       transport.conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
+               
"type='signal',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',sender='org.freedesktop.DBus',member='NameOwnerChanged'")
+
+       return ret, nil
+}
+
+func (s *ServerDbus) dbusPath() dbus.ObjectPath {
+       return "/org/gnome/CodeAssist/go"
+}
+
+func (s *ServerDbus) documentDbusPath(app *App, doc *DocumentDbus) dbus.ObjectPath {
+       return dbus.ObjectPath(fmt.Sprintf("%s/%v/documents/%v", s.dbusPath(), app.id, doc.Document.Id))
+}
+
+func (s *ServerDbus) makeApp(name string) *App {
+       app := &App{
+               id: s.nextid,
+               name: name,
+               docs: make(map[string]*DocumentDbus),
+               service: NewService(),
+       }
+
+       s.nextid++
+       s.apps[name] = app
+
+       return app
+}
+
+func (s *ServerDbus) ensureApp(name string) *App {
+       if app := s.apps[name]; app != nil {
+               return app
+       }
+
+       return s.makeApp(name)
+}
+
+func (s *ServerDbus) makeDocument(app *App, path string, clientPath string) *DocumentDbus {
+       doc := &Document{
+               Id: app.nextid,
+               Path: path,
+               ClientPath: clientPath,
+       }
+
+       ddoc := &DocumentDbus{
+               Document: doc,
+       }
+
+       s.transport.export(ddoc, s.documentDbusPath(app, ddoc))
+
+       app.nextid++
+       app.docs[path] = ddoc
+
+       return ddoc
+}
+
+func (s *ServerDbus) ensureDocument(app *App, path string, dataPath string, cursor int64) *DocumentDbus {
+       npath := filepath.Clean(path)
+
+       doc := app.docs[npath]
+
+       if doc == nil {
+               doc = s.makeDocument(app, npath, path)
+       }
+
+       doc.Document.DataPath = dataPath
+       doc.Document.Cursor = cursor
+
+       return doc
+}
+
+func (s *ServerDbus) parseOptions(options map[string]dbus.Variant) (Options, error) {
+       opts := make(map[string]interface{})
+
+       for k, v := range options {
+               opts[k] = v.Value()
+       }
+
+       var o Options
+       err := o.Parse(opts)
+
+       return o, err
+}
+
+func (s *ServerDbus) parse(appid string, path string, cursor int64, documents []OpenDocument, options 
map[string]dbus.Variant) ([]RemoteDocument, *dbus.Error) {
+       s.mutex.Lock()
+       app := s.ensureApp(appid)
+       s.mutex.Unlock()
+
+       o, err := s.parseOptions(options)
+
+       if err != nil {
+               return nil, NewDbusError("InvalidOptions", "%v", err)
+       }
+
+       app.mutex.Lock()
+       doc := s.ensureDocument(app, path, "", cursor)
+
+       unsaved := make([]UnsavedDocument, 0, len(documents))
+
+       for _, d := range documents {
+               cpath := filepath.Clean(d.Path)
+
+               if len(d.DataPath) != 0 && d.DataPath != d.Path {
+                       f, err := os.Open(d.DataPath)
+
+                       if err != nil {
+                               return nil, NewDbusError("ParseError", "%v", err)
+                       }
+
+                       defer f.Close()
+
+                       unsaved = append(unsaved, UnsavedDocument{
+                               Path: d.Path,
+                               Data: f,
+                       })
+               }
+
+               if doc := app.docs[cpath]; doc != nil {
+                       doc.Document.DataPath = d.DataPath
+               }
+       }
+
+       app.mutex.Unlock()
+
+       if err := app.service.Parse(doc.Document, unsaved, o); err != nil {
+               return nil, NewDbusError("ParseError", "%v", err)
+       }
+
+       return []RemoteDocument{
+               {path, s.documentDbusPath(app, doc)},
+       }, nil
+}
+
+func (s *ServerDbus) Parse(appid string, path string, cursor int64, dataPath string, options 
map[string]dbus.Variant) (dbus.ObjectPath, *dbus.Error) {
+       documents := []OpenDocument{
+               {path, dataPath},
+       }
+
+       ret, err := s.parse(appid, path, cursor, documents, options)
+
+       if err != nil {
+               return "", err
+       }
+
+       for _, v := range ret {
+               if v.Path == path {
+                       return v.ObjectPath, nil
+               }
+       }
+
+       return "", nil
+}
+
+func (s *ServerDbus) ParseAll(appid string, path string, cursor int64, documents []OpenDocument, options 
map[string]dbus.Variant) ([]RemoteDocument, *dbus.Error) {
+       return s.parse(appid, path, cursor, documents, options)
+}
+
+func (s *ServerDbus) disposeApp(app *App) {
+       for _, doc := range app.docs {
+               s.disposeDocument(app, doc)
+       }
+
+       app.docs = nil
+       delete(s.apps, app.name)
+
+       if len(s.apps) == 0 {
+               os.Exit(0)
+       }
+}
+
+func (s *ServerDbus) disposeDocument(app *App, doc *DocumentDbus) {
+       p := s.documentDbusPath(app, doc)
+       s.transport.unexport(doc, p)
+}
+
+func (s *ServerDbus) Dispose(appid string, path string) *dbus.Error {
+       s.mutex.Lock()
+       defer s.mutex.Unlock()
+
+       if app := s.apps[appid]; app != nil {
+               app.mutex.Lock()
+               defer app.mutex.Unlock()
+
+               cpath := filepath.Clean(path)
+
+               if doc := app.docs[cpath]; doc != nil {
+                       s.disposeDocument(app, doc)
+                       delete(app.docs, cpath)
+
+                       if len(app.docs) == 0 {
+                               s.disposeApp(app)
+                       }
+               }
+       }
+
+       return nil
+}
diff --git a/backends/go/service.go b/backends/go/service.go
index 24ed9a8..785ad15 100644
--- a/backends/go/service.go
+++ b/backends/go/service.go
@@ -1,5 +1,62 @@
 package main
 
+import (
+       "io"
+       "sync"
+)
+
+type Severity uint32
+
+const (
+       SeverityNone Severity = iota
+       SeverityInfo
+       SeverityWarning
+       SeverityDeprecated
+       SeverityError
+       SeverityFatal
+)
+
+type SourceLocation struct {
+       Line   int64
+       Column int64
+}
+
+type SourceRange struct {
+       File  int64
+       Start SourceLocation
+       End   SourceLocation
+}
+
+type UnsavedDocument struct {
+       Path string
+       Data io.ReadCloser
+}
+
+type Fixit struct {
+       Location    SourceRange
+       Replacement string
+}
+
+type Diagnostic struct {
+       Severity  Severity
+       Fixits    []Fixit
+       Locations []SourceRange
+       Message   string
+}
+
+type Document struct {
+       Id         uint64
+       Path       string
+       DataPath   string
+       ClientPath string
+       Cursor     int64
+
+       Diagnostics []Diagnostic
+
+       parsed *Parsed
+       mutex  sync.Mutex
+}
+
 type Service struct {
 }
 
@@ -7,19 +64,49 @@ func NewService() *Service {
        return &Service{}
 }
 
-func (s *Service) Parse(path string, cursor int64, unsaved []UnsavedDocument, options Options, doc 
*Document) (*Document, error) {
-       parsed, err := TheParser.Parse(path, cursor, unsaved, options)
+func (d *Document) process(parsed *Parsed) error {
+       var diagnostics []Diagnostic
 
-       if err != nil {
-               return doc, err
+       if parsed != nil {
+               diagnostics = make([]Diagnostic, len(parsed.Errors))
+
+               for i, err := range parsed.Errors {
+                       diagnostics[i] = Diagnostic{
+                               Severity: SeverityError,
+                               Locations: []SourceRange{
+                                       SourceRange{
+                                               Start: SourceLocation{
+                                                       Line:   int64(err.Pos.Line),
+                                                       Column: int64(err.Pos.Column),
+                                               },
+                                               End: SourceLocation{
+                                                       Line:   int64(err.Pos.Line),
+                                                       Column: int64(err.Pos.Column),
+                                               },
+                                       },
+                               },
+                               Message: err.Msg,
+                               Fixits:  []Fixit{},
+                       }
+               }
        }
 
-       if doc == nil {
-               doc = NewDocument(path)
+       d.mutex.Lock()
+       d.parsed = parsed
+       d.Diagnostics = diagnostics
+       d.mutex.Unlock()
+
+       return nil
+}
+
+func (s *Service) Parse(doc *Document, unsaved []UnsavedDocument, options Options) error {
+       parsed, err := TheParser.Parse(doc.Path, doc.Cursor, unsaved, options)
+
+       if err != nil {
+               return err
        }
 
-       doc.parsed = parsed
-       return doc, nil
+       return doc.process(parsed)
 }
 
 func (s *Service) Dispose(doc *Document) error {
diff --git a/backends/go/transport_dbus.go b/backends/go/transport_dbus.go
index be7e339..938d1f2 100644
--- a/backends/go/transport_dbus.go
+++ b/backends/go/transport_dbus.go
@@ -8,13 +8,12 @@ import (
 )
 
 type TransportDbus struct {
-       conn    *dbus.Conn
-       service *ServiceDbus
+       conn   *dbus.Conn
+       server *ServerDbus
 }
 
 type ObjectDbus interface {
        Introspect() *introspect.Node
-       Path() dbus.ObjectPath
 }
 
 func NewDbusError(name string, format string, args ...interface{}) *dbus.Error {
@@ -26,9 +25,18 @@ func NewDbusError(name string, format string, args ...interface{}) *dbus.Error {
        }
 }
 
-func (t *TransportDbus) export(obj ObjectDbus) error {
+func (t *TransportDbus) unexport(obj ObjectDbus, p dbus.ObjectPath) {
+       n := obj.Introspect()
+
+       for _, i := range n.Interfaces {
+               t.conn.Unexport(p, i.Name)
+       }
+
+       t.conn.Unexport(p, "org.freedesktop.DBus.Introspectable")
+}
+
+func (t *TransportDbus) export(obj ObjectDbus, p dbus.ObjectPath) error {
        n := obj.Introspect()
-       p := obj.Path()
 
        for _, i := range n.Interfaces {
                if err := t.conn.Export(obj, p, i.Name); err != nil {
@@ -64,12 +72,13 @@ func NewTransportDbus() (Transport, error) {
                conn: conn,
        }
 
-       t.service = NewServiceDbus(t)
+       server, err := NewServerDbus(t)
 
-       if err := t.export(t.service); err != nil {
+       if err != nil {
                return nil, err
        }
 
+       t.server = server
        return t, nil
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]