[gedit-code-assistance] Major rewrite to use gnome-code-assistance



commit c32aebd7c042ee9c31267a0fcf60fee7e40af70e
Author: Jesse van den Kieboom <jessevdk gmail com>
Date:   Fri Nov 8 14:15:23 2013 +0100

    Major rewrite to use gnome-code-assistance

 Makefile.am                                        |   29 +-
 backends/Makefile.am                               |   15 -
 backends/c/Makefile.am                             |   43 -
 backends/c/gcp-c-backend.vala                      |  230 -
 backends/c/gcp-c-compile-args.vala                 |  632 --
 backends/c/gcp-c-document.vala                     |  285 -
 backends/c/gcp-c-semantic-value.vala               |  195 -
 backends/c/gcp-c-translation-unit.vala             |  245 -
 backends/c/gcp-c-translator.vala                   |  135 -
 backends/c/gcpbackendc.plugin.in                   |   12 -
 backends/python/Makefile.am                        |    9 -
 backends/python/gcpbackendpython.plugin.in         |   13 -
 backends/python/gcpbackendpython/Makefile.am       |   11 -
 backends/python/gcpbackendpython/__init__.py       |   20 -
 backends/python/gcpbackendpython/backend.py        |   52 -
 backends/python/gcpbackendpython/document.py       |  141 -
 backends/xml/Makefile.am                           |    9 -
 backends/xml/gcpbackendxml.plugin.in               |   13 -
 backends/xml/gcpbackendxml/Makefile.am             |   11 -
 backends/xml/gcpbackendxml/__init__.py             |   20 -
 backends/xml/gcpbackendxml/backend.py              |   52 -
 backends/xml/gcpbackendxml/document.py             |  295 -
 configure.ac                                       |  214 +-
 data/Makefile.am                                   |   20 +-
 data/{gcp.css => codeassistance.css}               |   19 +-
 data/{gcp.plugin.in => codeassistance.plugin.in}   |    2 +-
 ...ome.gedit.plugins.codeassistance.gschema.xml.in |    9 +
 design.jft                                         |   40 -
 src/Makefile.am                                    |  176 +-
 ...p-activatable.vala => gca-app-activatable.vala} |    6 +-
 src/gca-backend-manager.vala                       |  131 +
 src/gca-backend.vala                               |  163 +
 src/gca-dbus.vala                                  |   83 +
 src/gca-diagnostic-colors.vala                     |  176 +
 ...ic-message.vala => gca-diagnostic-message.vala} |   42 +-
 src/gca-diagnostic-tags.vala                       |  171 +
 src/{gcp-diagnostic.vala => gca-diagnostic.vala}   |   96 +-
 src/gca-diagnostics.vala                           |  714 ++
 src/gca-document.vala                              |  296 +
 ...gcp-expand-range.vala => gca-expand-range.vala} |    2 +-
 src/{gcp-log.vala => gca-log.vala}                 |    4 +-
 src/{gcp-plugin.vala => gca-plugin.vala}           |   11 +-
 src/gca-remote-service.vala                        |   81 +
 ...llbar-marker.vala => gca-scrollbar-marker.vala} |   35 +-
 ...upport.vala => gca-semantic-value-support.vala} |    6 +-
 ...semantic-value.vala => gca-semantic-value.vala} |    4 +-
 ...gcp-source-index.vala => gca-source-index.vala} |  149 +-
 ...urce-location.vala => gca-source-location.vala} |   79 +-
 ...-support.vala => gca-source-range-support.vala} |    9 +-
 ...gcp-source-range.vala => gca-source-range.vala} |   64 +-
 ...upport.vala => gca-symbol-browser-support.vala} |    4 +-
 ...symbol-browser.vala => gca-symbol-browser.vala} |    2 +-
 ...gcp-unsaved-file.vala => gca-unsaved-file.vala} |    2 +-
 ...-activatable.vala => gca-view-activatable.vala} |    8 +-
 src/gca-view.vala                                  |  211 +
 src/gcp-backend-implementation.vala                |   90 -
 src/gcp-backend-manager.vala                       |  126 -
 src/gcp-backend.vala                               |   34 -
 src/gcp-diagnostic-colors.vala                     |  170 -
 src/gcp-diagnostic-support.vala                    |   97 -
 src/gcp-diagnostic-tags.vala                       |  185 -
 src/gcp-document.vala                              |  416 -
 src/gcp-utils-c.c                                  |   70 -
 src/gcp-utils-c.h                                  |   59 -
 src/gcp-view.vala                                  |  945 ---
 src/gcp.deps                                       |    8 -
 src/gcp.vala                                       |   50 -
 vapi/Makefile.am                                   |   17 +-
 vapi/clang.vapi                                    | 1206 ---
 vapi/config.vapi                                   |   12 -
 vapi/gca-utils.vapi                                |   12 +
 vapi/gcp-utils.vapi                                |    9 -
 vapi/gdk-3.0.deps                                  |    5 -
 vapi/gdk-3.0.vapi                                  | 1390 ----
 vapi/gedit-3.0.vapi                                |  449 --
 vapi/gobject-introspection-1.0.vapi                |   32 -
 vapi/gtk+-3.0.deps                                 |    6 -
 vapi/gtk+-3.0.vapi                                 | 8099 --------------------
 vapi/gtksourceview-3.0.vapi                        |  605 --
 vapi/libpeas-1.0.vapi                              |  118 -
 80 files changed, 2403 insertions(+), 17303 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index f4b790a..6e7f235 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,14 +1,13 @@
-SUBDIRS = data src vapi backends
-
 ACLOCAL_AMFLAGS = -I m4
 
 MAINTAINERCLEANFILES =                         \
+       INSTALL                         \
        aclocal.m4                      \
        config.guess                    \
        config.h.in                     \
        config.sub                      \
        depcomp                         \
-       gedit-code-assistance.doap      \
+       gnome-code-assistance.doap      \
        gtk-doc.make                    \
        install-sh                      \
        ltmain.sh                       \
@@ -23,7 +22,24 @@ MAINTAINERCLEANFILES =                       \
        m4/lt~obsolete.m4               \
        `find "$(srcdir)" -type f -name Makefile.in -print`
 
-dist-hook:
+CLEANFILES =
+EXTRA_DIST =
+GITIGNOREFILES =
+GITIGNOREDEPS =
+BUILT_SOURCES =
+DISTCLEANFILES =
+gsettings_SCHEMAS =
+
+geditcodeassistancedatadir = $(GEDIT_DATA_DIR)/codeassistance
+geditcodeassistanceplugindir = $(GEDIT_PLUGIN_DIR)
+
+include data/Makefile.am
+include src/Makefile.am
+include vapi/Makefile.am
+
+ GSETTINGS_RULES@
+
+dist-hook-changelog:
        @if test -d "$(srcdir)/.git"; \
        then \
                echo Creating ChangeLog && \
@@ -37,4 +53,9 @@ dist-hook:
                echo A git clone is required to generate a ChangeLog >&2; \
        fi
 
+dist-hook-built-sources:
+       cd $(distdir); rm -f $(BUILT_SOURCES)
+
+dist-hook: dist-hook-changelog dist-hook-built-sources
+
 -include $(top_srcdir)/git.mk
diff --git a/configure.ac b/configure.ac
index 2f6e27e..96e6d70 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10,106 +10,46 @@ AC_INIT([gedit-code-assistance],[gedit_code_assistance_version],[http://bugzilla
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_MACRO_DIR([m4])
 
-AC_ISC_POSIX
-AC_STDC_HEADERS
-AC_PROG_CC
-AM_PROG_CC_STDC
-AC_HEADER_STDC
 AM_PROG_LIBTOOL
 
-AM_PATH_PYTHON
-
-AM_INIT_AUTOMAKE([1.11 tar-ustar dist-xz no-dist-gzip -Wno-portability])
+AM_INIT_AUTOMAKE([1.11 tar-ustar dist-xz no-dist-gzip -Wno-portability subdir-objects])
 AM_MAINTAINER_MODE([enable])
 AM_SILENT_RULES([yes])
 
 AC_PROG_INSTALL
 AC_PROG_MAKE_SET
 
-AM_PROG_VALAC
-
-if test "x$VALAC" = "x" ; then
-       AC_MSG_ERROR([Cannot find the "valac" compiler])
-fi
-
-PKG_PROG_PKG_CONFIG
-
-dnl ================================================================
-dnl Start of pkg-config checks
-dnl ================================================================
-
-PKG_CHECK_MODULES(GCP, [
-       glib-2.0
-       gio-2.0
-       gee-1.0
-       libpeas-1.0 >= 1.5
-])
-
-GCP_LIBS="${GCP_LIBS}"
+AC_DEFUN([color_enable_var],
+[if test "x$1" != "xyes"; then
+       $2="\033@<:@31m$1\033@<:@0m"
+else
+       $2="\033@<:@32m$1\033@<:@0m"
+fi])
 
-AC_SUBST(GCP_LIBS)
-AC_SUBST(GCP_CFLAGS)
+AC_ARG_ENABLE([debug],
+              AS_HELP_STRING([--enable-debug],[enable debug build]),
+              [enable_debug=$enableval],
+              [enable_debug=no])
 
-AC_PATH_PROG([LLVM_CONFIG], [llvm-config], [])
+color_enable_var("$enable_debug", [enable_debug_msg])
 
-if test "x$LLVM_CONFIG" = "x"; then
-       clang_enabled=no
-       AC_MSG_WARN([could not find llvm-config])
-else
-       dnl find out the libdir of llvm
-       LLVM_LIBS=$($LLVM_CONFIG --ldflags)
-       LLVM_CFLAGS=$($LLVM_CONFIG --cflags)
-
-       dnl ================================================================
-       dnl Find clang headers and lib
-       dnl ================================================================
-       OLDCFLAGS="$CFLAGS"
-       OLDLDFLAGS="$LDFLAGS"
-
-       CFLAGS="$OLDCFLAGS $LLVM_CFLAGS"
-       LDFLAGS="$OLDLDFLAGS $LLVM_LIBS"
-
-       AC_CHECK_LIB([clang],
-                    [clang_createIndex],
-                    [LLVM_LIBS="$LLVM_LIBS -lclang"
-                     clang_enabled="yes"],
-                    [AC_MSG_WARN([could not find clang library])
-                     clang_enabled="no"])
-
-       if test "x$clang_enabled" = "xyes"; then
-               AC_CHECK_HEADER([clang-c/Index.h],
-                               [],
-                               [AC_MSG_WARN([could not find clang header Index.h])
-                                clang_enabled="no"])
-       fi
-
-       if test "x$clang_enabled" = "xyes"; then
-               LLVM_LIBS="$LLVM_LIBS -lclang"
-       fi
-
-       AC_SUBST(LLVM_CFLAGS)
-       AC_SUBST(LLVM_LIBS)
-
-       CFLAGS="$OLDCFLAGS"
-       LDFLAGS="$OLDLDFLAGS"
-
-       LLVM_VERSION=$($LLVM_CONFIG --version)
-       AC_DEFINE_UNQUOTED([LLVM_VERSION], "$LLVM_VERSION", [LLVM version])
-
-       AC_SUBST(LLVM_VERSION)
-fi
-
-AM_CONDITIONAL(CLANG_ENABLED, test "x$clang_enabled" = "xyes")
+AM_CONDITIONAL(ENABLE_DEBUG, test "x$enable_debug" = "xyes")
 
 AC_ARG_ENABLE([local],
               AS_HELP_STRING([--enable-local],[enable local install (in user directory)]),
               [enable_local=$enableval],
               [enable_local=no])
 
-dnl ================================================================
-dnl Find gedit
-dnl ================================================================
-PKG_CHECK_MODULES([GEDIT], [gedit >= 3.7.6])
+GEDIT_MODULES="gedit >= 3.8 gee-0.8"
+
+AM_PROG_VALAC
+PKG_PROG_PKG_CONFIG
+
+if test "x$VALAC" = "x"; then
+       AC_MSG_ERROR([Cannot find the "valac" compiler])
+fi
+
+PKG_CHECK_MODULES([GEDIT], $GEDIT_MODULES)
 
 gedit_prefix=`$PKG_CONFIG --variable=prefix gedit`
 
@@ -130,120 +70,28 @@ fi
 GEDIT_PLUGIN_DIR="$geditlibdir/gedit/plugins"
 GEDIT_DATA_DIR="$geditdatadir/gedit/plugins"
 
-GCP_BACKENDS_LIBS_DIR="$GEDIT_PLUGIN_DIR/gcp/backends"
-GCP_BACKENDS_DATA_DIR="$GEDIT_DATA_DIR/gcp/backends"
-
-GCP_LIBS_DIR="$GEDIT_PLUGIN_DIR/gcp"
-AC_SUBST(GCP_LIBS_DIR)
-
-GCP_DATA_DIR="$GEDIT_DATA_DIR/gcp"
-AC_SUBST(GCP_DATA_DIR)
-
 AC_SUBST(GEDIT_PLUGIN_DIR)
 AC_SUBST(GEDIT_DATA_DIR)
 
-AC_SUBST(GCP_BACKENDS_LIBS_DIR)
-AC_SUBST(GCP_BACKENDS_DATA_DIR)
-
 AC_SUBST(GEDIT_CFLAGS)
 AC_SUBST(GEDIT_LIBS)
 
-GOBJECT_INTROSPECTION_CHECK([0.9.3])
-
-dnl adl_RECURSIVE_EVAL(VALUE, RESULT)
-dnl =================================
-dnl Interpolate the VALUE in loop until it doesn't change,
-dnl and set the result to $RESULT.
-dnl WARNING: It's easy to get an infinite loop with some unsane input.
-AC_DEFUN([adl_RECURSIVE_EVAL],
-[_lcl_receval="$1"
-$2=`(test "x$prefix" = xNONE && prefix="$ac_default_prefix"
-     test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
-     _lcl_receval_old=''
-     while test "[$]_lcl_receval_old" != "[$]_lcl_receval"; do
-       _lcl_receval_old="[$]_lcl_receval"
-       eval _lcl_receval="\"[$]_lcl_receval\""
-     done
-     echo "[$]_lcl_receval")`])
-
-adl_RECURSIVE_EVAL("$GCP_BACKENDS_LIBS_DIR", [GCP_BACKENDS_DIR_EX])
-adl_RECURSIVE_EVAL("$GCP_BACKENDS_DATA_DIR", [GCP_BACKENDS_DATA_DIR_EX])
-
-adl_RECURSIVE_EVAL("$GCP_LIBS_DIR", [GCP_LIBS_DIR_EX])
-adl_RECURSIVE_EVAL("$GCP_DATA_DIR", [GCP_DATA_DIR_EX])
-
-AC_DEFINE_UNQUOTED([GCP_BACKENDS_DIR], "$GCP_BACKENDS_DIR_EX", [Backends dir])
-AC_DEFINE_UNQUOTED([GCP_BACKENDS_DATA_DIR], "$GCP_BACKENDS_DATA_DIR_EX", [Backends data dir])
-
-AC_DEFINE_UNQUOTED([GCP_LIBS_DIR], "$GCP_LIBS_DIR_EX", [Library dir])
-AC_DEFINE_UNQUOTED([GCP_DATA_DIR], "$GCP_DATA_DIR_EX", [Data dir])
-
-PYGOBJECT_REQUIRED=3.0.0
-
-AC_ARG_ENABLE([python],
-              AS_HELP_STRING([--enable-python[=@<:@no/auto/yes@:>@]],[Build with python support]),
-              [enable_python=$enableval],
-              [enable_python="auto"])
-
-if test "x$enable_python" = "xauto"; then
-       PKG_CHECK_EXISTS([pygobject-3.0 >= $PYGOBJECT_REQUIRED],
-                        [enable_python=yes],[enable_python=no])
-fi
-
-if test "x$enable_python" = "xyes"; then
-       PKG_CHECK_MODULES(PYTHON, [pygobject-3.0 >= $PYGOBJECT_REQUIRED])
-
-       pyoverridesdir=`$PYTHON -c "import gi; print(gi._overridesdir)"`
-       AC_SUBST(pyoverridesdir)
-fi
-
-AM_CONDITIONAL(PYTHON_ENABLED, test x"$enable_python" = "xyes")
-
-AC_ARG_ENABLE([xml],
-              AS_HELP_STRING([--enable-xml[=@<:@no/auto/yes@:>@]],[Build with XML support]),
-              [enable_xml=$enableval],
-              [enable_xml="auto"])
-
-if test "x$enable_xml" = "xauto"; then
-       PKG_CHECK_EXISTS([pygobject-3.0 >= $PYGOBJECT_REQUIRED],
-                        [enable_xml=yes],[enable_xml=no])
-fi
-
-AM_CONDITIONAL(XML_ENABLED, test x"$enable_xml" = "xyes")
+GLIB_GSETTINGS
 
 AC_CONFIG_FILES([
 Makefile
-data/Makefile
-data/gcp.plugin
-src/Makefile
-backends/Makefile
-backends/c/Makefile
-backends/c/gcpbackendc.plugin
-backends/python/Makefile
-backends/python/gcpbackendpython/Makefile
-backends/python/gcpbackendpython.plugin
-backends/xml/Makefile
-backends/xml/gcpbackendxml/Makefile
-backends/xml/gcpbackendxml.plugin
-vapi/Makefile
+data/codeassistance.plugin
+data/org.gnome.gedit.plugins.codeassistance.gschema.xml
 ])
 
 AC_OUTPUT
 
-echo "
+echo -e "
 
 Configuration:
 
-       Prefix:                 ${prefix}
-       Source code location:   ${srcdir}
-       Compiler:               ${CC}
-       valac:                  $VALAC
-       gedit plugin dir:       $GEDIT_PLUGIN_DIR
-       gedit data dir:         $GEDIT_DATA_DIR
-
-       backends:
-               c:              $clang_enabled ($LLVM_VERSION)
-               python:         $enable_python
-               xml:            $enable_xml
+       prefix:                 ${prefix}
+       source code location:   ${srcdir}
+       compiler:               ${CC}
+       debug:                  $enable_debug_msg
 "
-
diff --git a/data/Makefile.am b/data/Makefile.am
index 40fbd51..309a3c6 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,11 +1,15 @@
-plugindir = $(GEDIT_PLUGIN_DIR)
-plugin_DATA = gcp.plugin
+geditcodeassistanceplugin_DATA = data/codeassistance.plugin
+geditcodeassistancedata_DATA = data/codeassistance.css
 
-gcpdatadir = $(GEDIT_DATA_DIR)/gcp
-gcpdata_DATA = gcp.css
+gsettings_SCHEMAS += data/org.gnome.gedit.plugins.codeassistance.gschema.xml
 
-EXTRA_DIST = \
-       gcp.plugin \
-       gcp.css
+EXTRA_DIST += \
+       data/codeassistance.plugin \
+       data/codeassistance.css
 
--include $(top_srcdir)/git.mk
+CLEANFILES += $(geditcodeassistance_SCHEMAS)
+DISTCLEANFILES += $(geditcodeassistance_SCHEMAS)
+
+MAINTAINERCLEANFILES += $(geditcodeassistance_SCHEMAS:.xml=.valid)
+
+GITIGNOREDEPS += data/Makefile.am
diff --git a/data/gcp.css b/data/codeassistance.css
similarity index 75%
rename from data/gcp.css
rename to data/codeassistance.css
index b7c5c6a..8affbfe 100644
--- a/data/gcp.css
+++ b/data/codeassistance.css
@@ -1,10 +1,14 @@
-GcpDiagnosticMessage
+GcaDiagnosticMessage
 {
   border-width: 0px;
   border-radius: 10px;
 }
 
-GcpDiagnosticMessage.warning
+GcaDiagnosticMessage GtkLabel {
+  color: @infobar_fg_color;
+}
+
+GcaDiagnosticMessage.warning
 {
   background-image: -gtk-gradient(linear,
                                   left top,
@@ -13,7 +17,7 @@ GcpDiagnosticMessage.warning
                                   to(shade(@warning_bg_color, 0.75)));
 }
 
-GcpDiagnosticMessage.error
+GcaDiagnosticMessage.error
 {
   background-image: -gtk-gradient(linear,
                                   left top,
@@ -22,7 +26,7 @@ GcpDiagnosticMessage.error
                                   to(shade(@error_bg_color, 0.75)));
 }
 
-GcpDiagnosticMessage.info
+GcaDiagnosticMessage.info
 {
   background-image: -gtk-gradient(linear,
                                   left top,
@@ -31,11 +35,4 @@ GcpDiagnosticMessage.info
                                   to(shade(@info_bg_color, 0.75)));
 }
 
- binding-set GcpViewBindings
-{
-  bind "<Control>Up" { "find-reference" (-1) };
-  bind "<Control>Down" { "find-reference" (1) };
-  bind "<Control>Home" { "find-definition" () };
-}
-
 /* vi:ex:ts=2:et */
diff --git a/data/gcp.plugin.in b/data/codeassistance.plugin.in
similarity index 91%
rename from data/gcp.plugin.in
rename to data/codeassistance.plugin.in
index d00cb20..2fb99a6 100644
--- a/data/gcp.plugin.in
+++ b/data/codeassistance.plugin.in
@@ -1,5 +1,5 @@
 [Plugin]
-Module=gcp
+Module=codeassistance
 IAge=3
 Name=Code Assistance
 Description=Code assistance plugin for various languages
diff --git a/data/org.gnome.gedit.plugins.codeassistance.gschema.xml.in 
b/data/org.gnome.gedit.plugins.codeassistance.gschema.xml.in
new file mode 100644
index 0000000..ef8c204
--- /dev/null
+++ b/data/org.gnome.gedit.plugins.codeassistance.gschema.xml.in
@@ -0,0 +1,9 @@
+<schemalist>
+  <schema id="org.gnome.gedit.plugins.codeassistance" path="/org/gnome/gedit/plugins/codeassistance/">
+    <key name="language-mapping" type="a{ss}">
+      <default>{'cpp': 'c', 'objc': 'c', 'chdr': 'c'}</default>
+      <summary>Language Mapping</summary>
+      <description>A mapping from language id to backend id</description>
+    </key>
+  </schema>
+</schemalist>
diff --git a/src/Makefile.am b/src/Makefile.am
index 02ea9d6..cbef6ba 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,101 +1,75 @@
-INCLUDES =                             \
-       -I$(srcdir)                     \
-       -I$(top_srcdir)                 \
-       -DDATADIR=\""$(datadir)"\"
-
-plugindir = $(GEDIT_PLUGIN_DIR)
-plugin_LTLIBRARIES = libgcp.la
-
-vala_sources = \
-       gcp.vala \
-       gcp-plugin.vala \
-       gcp-app-activatable.vala \
-       gcp-view-activatable.vala \
-       gcp-source-location.vala \
-       gcp-source-range.vala \
-       gcp-expand-range.vala \
-       gcp-source-range-support.vala \
-       gcp-source-index.vala \
-       gcp-view.vala \
-       gcp-document.vala \
-       gcp-scrollbar-marker.vala \
-       gcp-backend.vala \
-       gcp-backend-implementation.vala \
-       gcp-backend-manager.vala \
-       gcp-unsaved-file.vala \
-       gcp-semantic-value.vala \
-       gcp-semantic-value-support.vala \
-       gcp-symbol-browser.vala \
-       gcp-symbol-browser-support.vala \
-       gcp-diagnostic.vala \
-       gcp-diagnostic-colors.vala \
-       gcp-diagnostic-tags.vala \
-       gcp-diagnostic-support.vala \
-       gcp-diagnostic-message.vala \
-       gcp-log.vala
-
-SOURCES = \
-       $(vala_sources) \
-       gcp-utils-c.c
-
-BUILT_SOURCES = \
-       gcp.vapi \
-       gcp.h
-
-NOINSTHFILES = \
-       gcp-utils-c.h
-
-EXTRA_DIST = $(NOINSTHFILES)
-
-libgcp_la_SOURCES = $(SOURCES)
-
-libgcp_la_VALAFLAGS = \
-       --vapidir $(top_srcdir)/vapi \
-       --header gcp.h \
-       --vapi gcp.vapi \
-       --library libgcp \
-       --gir Gcp-3.0.gir \
-       --pkg gio-2.0 \
-       --pkg gee-1.0 \
-       --pkg gcp-utils \
-       --pkg gtk+-3.0 \
-       --pkg gtksourceview-3.0 \
-       --pkg gedit-3.0 \
-       --pkg libpeas-1.0 \
-       --pkg gobject-introspection-1.0 \
-       --pkg posix \
-       --pkg config
-
-libgcp_la_CFLAGS = $(GCP_CFLAGS) $(GEDIT_CFLAGS) -I$(top_srcdir) -w
-libgcp_la_LDFLAGS = -module -shared -avoid-version $(GCP_LIBS) $(GEDIT_LIBS)
-
-INTROSPECTION_COMPILER_ARGS = --includedir $(GEDIT_GIR_DIR)
-
--include $(INTROSPECTION_MAKEFILE)
-
-girdir = $(GCP_DATA_DIR)/gir-1.0
-dist_gir_DATA = Gcp-3.0.gir
-
-typelibdir = $(GCP_LIBS_DIR)/girepository-1.0
-dist_typelib_DATA = $(dist_gir_DATA:.gir=.typelib)
-
-vapidir = $(datadir)/vala/vapi
-dist_vapi_DATA =       \
-       gcp.vapi        \
-       gcp.deps
-
-CLEANFILES =                           \
-       libgcp_la_vala.stamp
-
-MAINTAINERCLEANFILES =                 \
-       $(dist_gir_DATA)        \
-       $(dist_typelib_DATA)    \
-       $(BUILT_SOURCES)
-
-gcphdir = $(prefix)/include/gedit-$(GEDIT_API_VERSION)/gcp
-gcph_HEADERS = gcp.h
-
-GITIGNOREFILES =                       \
-       $(vala_sources:.vala=.c)
-
--include $(top_srcdir)/git.mk
+geditcodeassistanceplugin_LTLIBRARIES = src/libcodeassistance.la
+
+gedit_plugin_vala_sources =                                    \
+       src/gca-plugin.vala                                     \
+       src/gca-app-activatable.vala                            \
+       src/gca-view-activatable.vala                           \
+       src/gca-source-location.vala                            \
+       src/gca-source-range.vala                               \
+       src/gca-source-range-support.vala                       \
+       src/gca-expand-range.vala                               \
+       src/gca-source-index.vala                               \
+       src/gca-view.vala                                       \
+       src/gca-document.vala                                   \
+       src/gca-scrollbar-marker.vala                           \
+       src/gca-backend.vala                                    \
+       src/gca-backend-manager.vala                            \
+       src/gca-unsaved-file.vala                               \
+       src/gca-semantic-value.vala                             \
+       src/gca-semantic-value-support.vala                     \
+       src/gca-symbol-browser.vala                             \
+       src/gca-symbol-browser-support.vala                     \
+       src/gca-diagnostic.vala                                 \
+       src/gca-diagnostics.vala                                \
+       src/gca-diagnostic-colors.vala                          \
+       src/gca-diagnostic-tags.vala                            \
+       src/gca-diagnostic-message.vala                         \
+       src/gca-dbus.vala                                       \
+       src/gca-remote-service.vala                             \
+       src/gca-log.vala
+
+gedit_plugin_libcodeassistance_NOINSTHFILES =                  \
+       src/gca-utils-c.h
+
+BUILT_SOURCES +=                                               \
+       src/libcodeassistance.vapi                              \
+       $(srcdir)/src_libcodeassistance_la_vala.stamp
+
+EXTRA_DIST += $(gedit_plugin_libcodeassistance_NOINSTHFILES)
+
+src_libcodeassistance_la_SOURCES =             \
+       $(gedit_plugin_vala_sources)                            \
+       src/gca-utils-c.c
+
+src_libcodeassistance_la_VALAFLAGS =           \
+       --vapidir $(builddir)/vapi                              \
+       --vapi src/libcodeassistance.vapi                       \
+       --library libcodeassistance                             \
+       --pkg gio-unix-2.0                                      \
+       --pkg gee-0.8                                           \
+       --pkg gca-utils                                         \
+       --pkg gedit                                             \
+       --pkg libpeas-1.0                                       \
+       --target-glib=2.36                                      \
+       --thread
+
+if ENABLE_DEBUG
+src_libcodeassistance_la_VALAFLAGS += --debug
+endif
+
+src_libcodeassistance_la_CFLAGS = $(GEDIT_CFLAGS) -I$(top_srcdir) -w
+src_libcodeassistance_la_LDFLAGS = -module -shared -avoid-version $(GEDIT_LIBS)
+
+CLEANFILES +=                                                  \
+       $(gedit_plugin_vala_sources:.vala=.c)                   \
+       src_libcodeassistance_la_vala.stamp
+
+GITIGNOREFILES +=                                              \
+       src/libcodeassistance.vapi                              \
+       src/$(DEPDIR)                                           \
+       src/*.lo                                                \
+       src/*.o                                                 \
+       src/.libs                                               \
+       src/.dirstamp
+
+GITIGNOREDEPS += src/Makefile.am
diff --git a/src/gcp-app-activatable.vala b/src/gca-app-activatable.vala
similarity index 86%
rename from src/gcp-app-activatable.vala
rename to src/gca-app-activatable.vala
index 09e6a68..1a7972c 100644
--- a/src/gcp-app-activatable.vala
+++ b/src/gca-app-activatable.vala
@@ -1,11 +1,11 @@
 using Gtk;
 
-namespace Gcp
+namespace Gca
 {
 
 class AppActivatable : Peas.ExtensionBase, Gedit.AppActivatable
 {
-       public Gedit.App app {get; set;}
+       public Gedit.App app { owned get; construct; }
 
        private CssProvider d_provider;
 
@@ -14,7 +14,7 @@ class AppActivatable : Peas.ExtensionBase, Gedit.AppActivatable
                d_provider = new CssProvider();
 
                File file = File.new_for_path(get_data_dir());
-               File child = file.get_child("gcp.css");
+               File child = file.get_child("codeassistance.css");
 
                try
                {
diff --git a/src/gca-backend-manager.vala b/src/gca-backend-manager.vala
new file mode 100644
index 0000000..29b7217
--- /dev/null
+++ b/src/gca-backend-manager.vala
@@ -0,0 +1,131 @@
+/*
+ * This file is part of gedit-code-assistant.
+ *
+ * Copyright (C) 2011 - Jesse van den Kieboom
+ *
+ * gedit-code-assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit-code-assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Gca
+{
+
+class BackendManager
+{
+       private static BackendManager s_instance;
+       private Gee.HashMap<string, Backend?> d_backends;
+       private Gee.HashMap<string, string> d_language_mapping;
+       private Settings? d_settings;
+
+       private BackendManager()
+       {
+               d_backends = new Gee.HashMap<string, Backend?>();
+
+               d_settings = null;
+
+               var source = SettingsSchemaSource.get_default();
+               var schema = "org.gnome.gedit.plugins.codeassistance";
+
+               if (source.lookup(schema, true) != null)
+               {
+                       d_settings = new Settings(schema);
+               }
+
+               update_language_mapping();
+
+               if (d_settings != null)
+               {
+                       d_settings.changed["language-mapping"].connect(() => {
+                               update_language_mapping();
+                       });
+               }
+       }
+
+       private void update_language_mapping()
+       {
+               d_language_mapping = new Gee.HashMap<string, string>();
+
+               if (d_settings == null)
+               {
+                       d_language_mapping["cpp"] = "c";
+                       d_language_mapping["chdr"] = "c";
+                       d_language_mapping["objc"] = "c";
+
+                       return;
+               }
+
+               var mapping = d_settings.get_value("language-mapping");
+
+               if (mapping == null)
+               {
+                       return;
+               }
+
+               var iter = mapping.iterator();
+
+               string key = null;
+               string val = null;
+
+               while (iter.next("{ss}", &key, &val))
+               {
+                       d_language_mapping[key] = val;
+               }
+       }
+
+       public async Backend? backend(string language)
+       {
+               var lang = language;
+
+               if (d_language_mapping.has_key(language))
+               {
+                       lang = d_language_mapping[language];
+               }
+
+               if (d_backends.has_key(lang))
+               {
+                       return d_backends[lang];
+               }
+
+               Backend? backend;
+
+               try
+               {
+                       backend = yield Backend.create(lang);
+               }
+               catch (Error e)
+               {
+                       Log.debug("Failed to obtain backend: %s\n", e.message);
+                       backend = null;
+               }
+
+               d_backends[lang] = backend;
+               return backend;
+       }
+
+       public static BackendManager instance
+       {
+               get
+               {
+                       if (s_instance == null)
+                       {
+                               s_instance = new BackendManager();
+                       }
+
+                       return s_instance;
+               }
+       }
+}
+
+}
+
+/* vi:ex:ts=4 */
diff --git a/src/gca-backend.vala b/src/gca-backend.vala
new file mode 100644
index 0000000..ceff288
--- /dev/null
+++ b/src/gca-backend.vala
@@ -0,0 +1,163 @@
+/*
+ * This file is part of gedit-code-assistant.
+ *
+ * Copyright (C) 2011 - Jesse van den Kieboom
+ *
+ * gedit-code-assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit-code-assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Gca
+{
+
+class Backend : Object
+{
+       private Gee.ArrayList<View> d_views;
+       private string d_name;
+       private DBus.Service d_service;
+       private RemoteServices d_supported_services;
+
+       public static async Backend create(string language) throws IOError, DBusError
+       {
+               var name = "org.gnome.CodeAssist." + language;
+               var path = "/org/gnome/CodeAssist/" + language;
+
+               var service = yield Bus.get_proxy<DBus.Service>(BusType.SESSION, name, path);
+               var services = yield service.supported_services();
+
+               return new Backend(name, service, services);
+       }
+
+       private Backend(string name, DBus.Service service, string[] services)
+       {
+               d_name = name;
+               d_service = service;
+
+               d_views = new Gee.ArrayList<View>();
+               d_supported_services = 0;
+
+               foreach (var s in services)
+               {
+                       d_supported_services |= RemoteServices.parse(s);
+               }
+       }
+
+       public bool supports(RemoteServices services)
+       {
+               return (d_supported_services & services) != 0;
+       }
+
+       public void register(View view)
+       {
+               d_views.add(view);
+
+               view.changed.connect(on_view_changed);
+       }
+
+       public void unregister(View view)
+       {
+               view.changed.disconnect(on_view_changed);
+               d_views.remove(view);
+       }
+
+       private async DBus.UnsavedDocument? unsaved_document(View v)
+       {
+               var doc = v.document;
+
+               if (doc.is_modified)
+               {
+                       try
+                       {
+                               var dp = yield doc.unsaved_data_path();
+
+                               return DBus.UnsavedDocument() {
+                                       path = doc.path,
+                                       data_path = dp
+                               };
+                       }
+                       catch (Error e)
+                       {
+                               Log.debug("Failed to get unsaved document: %s", e.message);
+                       }
+               }
+
+               return null;
+       }
+
+       private async DBus.UnsavedDocument[] unsaved_documents(View primary)
+       {
+               if ((d_supported_services & RemoteServices.MULTI_DOC) == 0)
+               {
+                       var unsaved = yield unsaved_document(primary);
+
+                       if (unsaved == null)
+                       {
+                               return new DBus.UnsavedDocument[0];
+                       }
+
+                       return new DBus.UnsavedDocument[] {unsaved};
+               }
+
+               var unsaved = new DBus.UnsavedDocument[d_views.size];
+               unsaved.length = 0;
+
+               foreach (var v in d_views)
+               {
+                       var u = yield unsaved_document(v);
+
+                       if (u != null)
+                       {
+                               unsaved += u;
+                       }
+               }
+
+               return unsaved;
+       }
+
+       private void parse(View view)
+       {
+               unsaved_documents.begin(view, (obj, res) => {
+                       var unsaved = unsaved_documents.end(res);
+
+                       var path = view.document.path;
+                       var cursor = view.document.cursor;
+
+                       var options = new HashTable<string, Variant>(str_hash, str_equal);
+
+                       d_service.parse.begin(path, cursor, unsaved, options, (obj, res) => {
+                               ObjectPath ret;
+
+                               try
+                               {
+                                       ret = d_service.parse.end(res);
+                               }
+                               catch (Error e)
+                               {
+                                       Log.debug("Failed to parse: %s", e.message);
+                                       return;
+                               }
+
+                               view.update(new RemoteDocument(d_name, ret));
+                       });
+               });
+       }
+
+       private void on_view_changed(View view)
+       {
+               parse(view);
+       }
+}
+
+}
+
+/* vi:ex:ts=4 */
diff --git a/src/gca-dbus.vala b/src/gca-dbus.vala
new file mode 100644
index 0000000..3ef224a
--- /dev/null
+++ b/src/gca-dbus.vala
@@ -0,0 +1,83 @@
+/*
+ * This file is part of gedit-code-assistant.
+ *
+ * Copyright (C) 2013 - Jesse van den Kieboom
+ *
+ * gedit-code-assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit-code-assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Gca.DBus
+{
+
+public struct UnsavedDocument
+{
+       public string path;
+       public string data_path;
+}
+
+public struct SourceLocation
+{
+       public int64 line;
+       public int64 column;
+}
+
+public struct SourceRange
+{
+       public int64 file;
+
+       public SourceLocation start;
+       public SourceLocation end;
+}
+
+public struct Fixit
+{
+       public SourceRange location;
+       public string replacement;
+}
+
+public struct Diagnostic
+{
+       public uint32 severity;
+       public Fixit[] fixits;
+       public SourceRange[] locations;
+       public string message;
+}
+
+[DBus(name = "org.gnome.CodeAssist.Service")]
+interface Service : Object
+{
+       public abstract async ObjectPath parse(string                     path,
+                                              int64                      cursor,
+                                              UnsavedDocument[]          unsaved,
+                                              HashTable<string, Variant> options) throws DBusError;
+
+       public abstract async void dispose(string path) throws DBusError;
+
+       public abstract async string[] supported_services() throws DBusError;
+}
+
+[DBus(name = "org.gnome.CodeAssist.Document")]
+interface Document : Object
+{
+}
+
+[DBus(name = "org.gnome.CodeAssist.Diagnostics")]
+interface Diagnostics : Object
+{
+       public abstract async Diagnostic[] diagnostics() throws DBusError;
+}
+
+}
+
+/* vi:ex:ts=4 */
diff --git a/src/gca-diagnostic-colors.vala b/src/gca-diagnostic-colors.vala
new file mode 100644
index 0000000..e574b17
--- /dev/null
+++ b/src/gca-diagnostic-colors.vala
@@ -0,0 +1,176 @@
+/*
+ * This file is part of gedit-code-assistant.
+ *
+ * Copyright (C) 2011 - Jesse van den Kieboom
+ *
+ * gedit-code-assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit-code-assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Gtk;
+
+namespace Gca
+{
+
+class DiagnosticColors
+{
+       private Gdk.RGBA d_errorColor;
+       private Gdk.RGBA d_warningColor;
+       private Gdk.RGBA d_infoColor;
+
+       public DiagnosticColors(StyleContext context)
+       {
+               d_errorColor = update_color(context,
+                            "error_bg_color",
+                            {1, 0, 0, 1},
+                            0.5);
+
+               d_warningColor = update_color(context,
+                            "warning_bg_color",
+                            {1, 0.5, 0, 1},
+                            0.5);
+
+               d_infoColor = update_color(context,
+                            "info_bg_color",
+                            {0, 0, 1, 1},
+                            0.5);
+       }
+
+       private Gdk.RGBA mix_colors(Gdk.RGBA source, Gdk.RGBA dest)
+       {
+               Gdk.RGBA mixed = {0, 0, 0, 0};
+
+               mixed.alpha = source.alpha + dest.alpha * (1 - source.alpha);
+
+               mixed.red = (source.red * source.alpha +
+                            dest.red * dest.alpha * (1 - source.alpha)) / mixed.alpha;
+
+               mixed.green = (source.green * source.alpha +
+                            dest.green * dest.alpha * (1 - source.alpha)) / mixed.alpha;
+
+               mixed.blue = (source.blue * source.alpha +
+                            dest.blue * dest.alpha * (1 - source.alpha)) / mixed.alpha;
+
+               return mixed;
+       }
+
+       public void mix_in_widget(Widget widget)
+       {
+               StyleContext ctx = widget.get_style_context();
+
+               ctx.save();
+               ctx.add_class(STYLE_CLASS_VIEW);
+
+               var dest = ctx.get_background_color(widget.get_state_flags());
+               mix_in_color(widget, dest);
+
+               ctx.restore();
+       }
+
+       public void mix_in_color(Widget widget, Gdk.RGBA dest)
+       {
+               StyleContext ctx = widget.get_style_context();
+
+               ctx.save();
+
+               ctx.add_class(STYLE_CLASS_VIEW);
+
+               d_errorColor = mix_colors(update_color(ctx,
+                                                      "error_bg_color",
+                                                      {1, 0, 0, 1},
+                                                      0.5), dest);
+
+               d_warningColor = mix_colors(update_color(ctx,
+                                                        "warning_bg_color",
+                                                        {1, 0.5, 0, 1},
+                                                        0.5), dest);
+
+               d_infoColor = mix_colors(update_color(ctx,
+                                                     "info_bg_color",
+                                                     {0, 0, 1, 1},
+                                                     0.5), dest);
+
+               ctx.restore();
+       }
+
+       public Gdk.RGBA? get(Diagnostic.Severity severity)
+       {
+               switch (severity)
+               {
+                       case Diagnostic.Severity.INFO:
+                               return d_infoColor;
+                       case Diagnostic.Severity.WARNING:
+                               return d_warningColor;
+                       case Diagnostic.Severity.ERROR:
+                       case Diagnostic.Severity.FATAL:
+                               return d_errorColor;
+                       default:
+                               return null;
+               }
+       }
+
+       public Gdk.RGBA error_color
+       {
+               get { return d_errorColor; }
+       }
+
+       public Gdk.RGBA warning_color
+       {
+               get { return d_warningColor; }
+       }
+
+       public Gdk.RGBA info_color
+       {
+               get { return d_infoColor; }
+       }
+
+       private Gdk.RGBA update_color(StyleContext context,
+                                     string color_name,
+                                     Gdk.RGBA defcol,
+                                     double alpha)
+       {
+               Gdk.RGBA col;
+
+               if (!context.lookup_color(color_name, out col))
+               {
+                       col = defcol;
+               }
+
+               double s = 0;
+
+               var max = double.max(col.red, double.max(col.green, col.blue));
+               var min = double.min(col.red, double.min(col.green, col.blue));
+
+               var dm = max - min;
+
+               if (dm != 0)
+               {
+                       s = dm / max;
+               }
+
+               if (s < 0.5)
+               {
+                       col.red *= 0.5;
+                       col.blue *= 0.5;
+                       col.green *= 0.5;
+               }
+
+               col.alpha *= alpha;
+
+               return col;
+       }
+}
+
+}
+
+/* vi:ex:ts=4 */
diff --git a/src/gcp-diagnostic-message.vala b/src/gca-diagnostic-message.vala
similarity index 91%
rename from src/gcp-diagnostic-message.vala
rename to src/gca-diagnostic-message.vala
index e5ca553..ae7a765 100644
--- a/src/gcp-diagnostic-message.vala
+++ b/src/gca-diagnostic-message.vala
@@ -1,22 +1,22 @@
 using Gtk;
 using Gee;
 
-namespace Gcp
+namespace Gca
 {
 
-public class DiagnosticMessage : EventBox
+class DiagnosticMessage : EventBox
 {
        private Diagnostic[] d_diagnostics;
        private Box? d_vbox;
        private DiagnosticColors d_colors;
-       private unowned GtkSource.View? d_view;
+       private unowned SourceView? d_view;
        private Diagnostic.Severity d_rulingSeverity;
        private bool d_inserted;
        private int d_width;
        private int d_height;
        private bool d_updating;
 
-       public DiagnosticMessage(GtkSource.View view, Diagnostic[] diagnostics)
+       public DiagnosticMessage(SourceView view, Diagnostic[] diagnostics)
        {
                d_diagnostics = diagnostics;
                d_view = view;
@@ -116,8 +116,7 @@ public class DiagnosticMessage : EventBox
                ctx.save();
 
                ctx.add_class(STYLE_CLASS_VIEW);
-               Gdk.RGBA color;
-               ctx.get_color(StateFlags.NORMAL, out color);
+               //var color = ctx.get_color(StateFlags.NORMAL);
 
                ctx.restore();
 
@@ -125,7 +124,7 @@ public class DiagnosticMessage : EventBox
 
                foreach (Diagnostic d in d_diagnostics)
                {
-                       Label label = new Label();
+                       Label label = new Label(null);
 
                        if (ismixed)
                        {
@@ -196,6 +195,8 @@ public class DiagnosticMessage : EventBox
                {
                        d_diagnostics = value;
 
+                       stderr.printf("set diagnostics\n");
+
                        update();
                }
        }
@@ -269,8 +270,6 @@ public class DiagnosticMessage : EventBox
                                expand_range(topx, bottomx, y, r.start);
                                expand_range(topx, bottomx, y, r.end);
                        }
-
-                       expand_range(topx, bottomx, y, d.location);
                }
 
                // Position the message depending on where we can find the largest
@@ -332,7 +331,6 @@ public class DiagnosticMessage : EventBox
                        d_view.add_child_in_window(this, TextWindowType.TEXT, 0, 0);
                }
 
-
                int minwidth;
                base.get_preferred_width(null, out minwidth);
 
@@ -358,6 +356,15 @@ public class DiagnosticMessage : EventBox
                return SizeRequestMode.HEIGHT_FOR_WIDTH;
        }
 
+       protected override void get_preferred_height(out int minimum_height,
+                                                    out int natural_height)
+       {
+               int minwidth;
+
+               get_preferred_width(out minwidth, null);
+               get_preferred_height_for_width(minwidth, out minimum_height, out natural_height);
+       }
+
        protected override void get_preferred_width(out int minimum_width,
                                                    out int natural_width)
        {
@@ -412,19 +419,8 @@ public class DiagnosticMessage : EventBox
                ctx.save();
                add_class_for_severity(ctx);
 
-               render_background(get_style_context(),
-                                 context,
-                                 0,
-                                 0,
-                                 alloc.width,
-                                 alloc.height);
-
-               render_frame(get_style_context(),
-                            context,
-                            0,
-                            0,
-                            alloc.width,
-                            alloc.height);
+               ctx.render_background(context, 0, 0, alloc.width, alloc.height);
+               ctx.render_frame(context, 0, 0, alloc.width, alloc.height);
 
                ctx.save();
 
diff --git a/src/gca-diagnostic-tags.vala b/src/gca-diagnostic-tags.vala
new file mode 100644
index 0000000..ee61939
--- /dev/null
+++ b/src/gca-diagnostic-tags.vala
@@ -0,0 +1,171 @@
+/*
+ * This file is part of gedit-code-assistant.
+ *
+ * Copyright (C) 2011 - Jesse van den Kieboom
+ *
+ * gedit-code-assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit-code-assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Gtk;
+
+namespace Gca
+{
+
+class DiagnosticTags : Object
+{
+       private unowned TextView d_view;
+       private unowned TextBuffer? d_buffer;
+
+       private TextTag? d_infoTag;
+       private TextTag? d_warningTag;
+       private TextTag? d_errorTag;
+       private TextTag? d_fixitTag;
+
+       public DiagnosticTags(TextView view)
+       {
+               d_view = view;
+
+               d_view.style_updated.connect(on_style_updated);
+               d_view.notify["buffer"].connect(on_buffer_changed);
+
+               d_buffer = view.buffer;
+
+               update_tags();
+       }
+
+       ~DiagnosticTags()
+       {
+               remove_tags();
+
+               d_view.style_updated.disconnect(on_style_updated);
+       }
+
+       private TextTag ensure_tag(ref TextTag? tag, string name)
+       {
+               if (tag == null)
+               {
+                       tag = d_buffer.create_tag(name);
+               }
+
+               return tag;
+       }
+
+       private void update_tag(ref TextTag? tag,
+                               string name,
+                               Gdk.RGBA col)
+       {
+               ensure_tag(ref tag, name);
+
+               tag.background_rgba = col;
+               tag.background_full_height = true;
+       }
+
+       private void update_tags()
+       {
+               DiagnosticColors colors;
+
+               colors = new DiagnosticColors(d_view.get_style_context());
+               colors.mix_in_widget(d_view);
+
+               update_tag(ref d_infoTag,
+                          "Gca.Info",
+                          colors.info_color);
+
+               update_tag(ref d_warningTag,
+                          "Gca.Warning",
+                          colors.warning_color);
+
+               update_tag(ref d_errorTag,
+                          "Gca.Error",
+                          colors.error_color);
+
+               ensure_tag(ref d_fixitTag, "Gca.Fixit");
+               d_fixitTag.strikethrough = true;
+       }
+
+       public TextTag? error_tag
+       {
+               get { return d_errorTag; }
+       }
+
+       public TextTag? warning_tag
+       {
+               get { return d_warningTag; }
+       }
+
+       public TextTag? info_tag
+       {
+               get { return d_infoTag; }
+       }
+
+       public TextTag? fixit_tag
+       {
+               get { return d_fixitTag; }
+       }
+
+       public new TextTag? get(Diagnostic.Severity severity)
+       {
+               switch (severity)
+               {
+                       case Diagnostic.Severity.INFO:
+                               return d_infoTag;
+                       case Diagnostic.Severity.WARNING:
+                               return d_warningTag;
+                       case Diagnostic.Severity.ERROR:
+                       case Diagnostic.Severity.FATAL:
+                               return d_errorTag;
+                       default:
+                               return null;
+               }
+       }
+
+       private void remove_tag(ref TextTag? tag)
+       {
+               if (d_buffer != null && tag != null)
+               {
+                       d_buffer.tag_table.remove(tag);
+                       tag = null;
+               }
+       }
+
+       private void remove_tags()
+       {
+               remove_tag(ref d_errorTag);
+               remove_tag(ref d_warningTag);
+               remove_tag(ref d_infoTag);
+               remove_tag(ref d_fixitTag);
+       }
+
+       private void on_buffer_changed()
+       {
+               remove_tags();
+
+               d_buffer = d_view.buffer;
+
+               d_errorTag = null;
+               d_warningTag = null;
+               d_infoTag = null;
+
+               update_tags();
+       }
+
+       private void on_style_updated()
+       {
+               update_tags();
+       }
+}
+
+}
+
+/* vi:ex:ts=4 */
diff --git a/src/gcp-diagnostic.vala b/src/gca-diagnostic.vala
similarity index 67%
rename from src/gcp-diagnostic.vala
rename to src/gca-diagnostic.vala
index a8df9f5..b7ae262 100644
--- a/src/gcp-diagnostic.vala
+++ b/src/gca-diagnostic.vala
@@ -19,19 +19,19 @@
 
 using Gee;
 
-namespace Gcp
+namespace Gca
 {
 
-public class Diagnostic : Object, SourceRangeSupport
+class Diagnostic : Object, SourceRangeSupport
 {
        public enum Severity
        {
                NONE,
                INFO,
                WARNING,
+               DEPRECATED,
                ERROR,
-               FATAL,
-               NUM;
+               FATAL;
 
                public string to_string()
                {
@@ -43,8 +43,12 @@ public class Diagnostic : Object, SourceRangeSupport
                                        return "Info";
                                case WARNING:
                                        return "Warning";
+                               case DEPRECATED:
+                                       return "Deprecated";
                                case ERROR:
                                        return "Error";
+                               case FATAL:
+                                       return "Fatal";
                                default:
                                        return "Unknown";
                        }
@@ -55,54 +59,57 @@ public class Diagnostic : Object, SourceRangeSupport
        {
                public SourceRange range;
                public string replacement;
+
+               public static Fixit from_dbus(DBus.Fixit fixit)
+               {
+                       return Fixit() {
+                               range = SourceRange.from_dbus(fixit.location),
+                               replacement = fixit.replacement
+                       };
+               }
+
        }
 
-       private SourceLocation d_location;
-       private SourceRange[] d_ranges;
-       private SourceRange[]? d_rangesAndLocation;
+       private SourceRange[] d_location;
        private Fixit[] d_fixits;
        private Severity d_severity;
        private string d_message;
 
+       public Diagnostic.from_dbus(DBus.Diagnostic diagnostic)
+       {
+               var f = new Fixit[diagnostic.fixits.length];
+
+               for (var i = 0; i < diagnostic.fixits.length; ++i)
+               {
+                       f[i] = Fixit.from_dbus(diagnostic.fixits[i]);
+               }
+
+               var l = new SourceRange[diagnostic.locations.length];
+
+               for (var i = 0; i < diagnostic.locations.length; ++i)
+               {
+                       l[i] = SourceRange.from_dbus(diagnostic.locations[i]);
+               }
+
+               this((Severity)diagnostic.severity, l, f, diagnostic.message);
+       }
+
        public Diagnostic(Severity       severity,
-                         SourceLocation location,
-                         SourceRange[]  ranges,
+                         SourceRange[]  location,
                          Fixit[]        fixits,
                          string         message)
        {
                d_severity = severity;
                d_location = location;
-               d_ranges = ranges;
                d_fixits = fixits;
                d_message = message;
        }
 
-       public SourceLocation location
-       {
-               get { return d_location; }
-       }
-
-       public SourceRange? range
-       {
-               owned get { return d_location.range; }
-       }
-
        public SourceRange[] ranges
        {
                owned get
                {
-                       if (d_rangesAndLocation == null)
-                       {
-                               d_rangesAndLocation = new SourceRange[d_ranges.length + 1];
-                               d_rangesAndLocation[0] = d_location.range;
-
-                               for (int i = 0; i < d_ranges.length; ++i)
-                               {
-                                       d_rangesAndLocation[i + 1] = d_ranges[i];
-                               }
-                       }
-
-                       return d_rangesAndLocation;
+                       return d_location;
                }
        }
 
@@ -121,28 +128,21 @@ public class Diagnostic : Object, SourceRangeSupport
                get { return d_message; }
        }
 
-       private string loc_string()
+       public SourceRange[] location
        {
-               string[] r = new string[d_ranges.length];
-
-               for (int i = 0; i < d_ranges.length; ++i)
-               {
-                       r[i] = d_ranges[i].to_string();
-               }
+               get { return d_location; }
+       }
 
-               string loc = "%s".printf(d_location.to_string());
+       private string loc_string()
+       {
+               string[] r = new string[d_location.length];
 
-               if (r.length > 0)
+               for (int i = 0; i < d_location.length; ++i)
                {
-                       loc = "%s at %s".printf(string.joinv(", ", r), loc);
+                       r[i] = d_location[i].to_string();
                }
 
-               return loc;
-       }
-
-       public string to_string()
-       {
-               return "%s %s: %s".printf(d_severity.to_string(), loc_string(), d_message);
+               return string.joinv(", ", r);
        }
 
        public string to_markup(bool include_severity = true)
diff --git a/src/gca-diagnostics.vala b/src/gca-diagnostics.vala
new file mode 100644
index 0000000..4bb5a57
--- /dev/null
+++ b/src/gca-diagnostics.vala
@@ -0,0 +1,714 @@
+/*
+ * This file is part of gedit-code-assistant.
+ *
+ * Copyright (C) 2011 - Jesse van den Kieboom
+ *
+ * gedit-code-assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit-code-assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Gca
+{
+
+class DiagnosticService : RemoteService, Object
+{
+       private Diagnostics d_diagnostics;
+       private DBus.Diagnostics d_proxy;
+       private ObjectPath? d_path;
+
+       public RemoteServices services()
+       {
+               return RemoteServices.DIAGNOSTICS;
+       }
+
+       public void update(View view, RemoteDocument document)
+       {
+               if (d_diagnostics == null)
+               {
+                       d_diagnostics = new Diagnostics(view);
+               }
+
+               if (d_path != document.path)
+               {
+                       d_proxy = null;
+                       d_path = null;
+               }
+
+               if (d_proxy == null)
+               {
+                       document.get_proxy.begin<DBus.Diagnostics>((obj, res) => {
+                               try
+                               {
+                                       d_proxy = document.get_proxy<DBus.Diagnostics>.end(res);
+                                       update_proxy();
+                               }
+                               catch (IOError e)
+                               {
+                                       Log.debug("Failed to get diagnostics proxy: %s", e.message);
+                               }
+                       });
+               }
+               else
+               {
+                       update_proxy();
+               }
+       }
+
+       private void update_proxy()
+       {
+               d_proxy.diagnostics.begin((obj, res) => {
+                       try
+                       {
+                               var ret = d_proxy.diagnostics.end(res);
+                               d_diagnostics.update(transform(ret));
+                       }
+                       catch (Error e)
+                       {
+                               Log.debug("Failed to call diagnostics: %s", e.message);
+                       }
+               });
+       }
+
+       private Diagnostic[] transform(DBus.Diagnostic[] diagnostics)
+       {
+               var ret = new Diagnostic[diagnostics.length];
+
+               for (var i = 0; i < ret.length; ++i)
+               {
+                       ret[i] = new Diagnostic.from_dbus(diagnostics[i]);
+               }
+
+               return ret;
+       }
+
+       public void destroy()
+       {
+               if (d_diagnostics != null)
+               {
+                       d_diagnostics.destroy();
+                       d_diagnostics = null;
+               }
+       }
+}
+
+class Diagnostics : Object
+{
+       private View? d_view;
+       private SourceIndex<Diagnostic> d_index;
+       private DiagnosticTags d_tags;
+
+       private Gee.HashMap<Gtk.TextMark, Gdk.RGBA?> d_diagnostics_at_end;
+       private Diagnostic[] d_cursor_diagnostics;
+       private DiagnosticMessage? d_cursor_diagnostic_message;
+       private uint d_last_marker_id;
+
+       public static string error_mark_category
+       {
+               get { return "Gca.Document.ErrorCategory"; }
+       }
+
+       public static string error_icon_name
+       {
+               get { return "dialog-error-symbolic"; }
+       }
+
+       public static string warning_mark_category
+       {
+               get { return "Gca.Document.WarningCategory"; }
+       }
+
+       public static string warning_icon_name
+       {
+               get { return "dialog-warning-symbolic"; }
+       }
+
+       public static string info_mark_category
+       {
+               get { return "Gca.Document.InfoCategory"; }
+       }
+
+       public static string info_icon_name
+       {
+               get { return "dialog-information-symbolic"; }
+       }
+
+       public Diagnostics(View view)
+       {
+               d_view = view;
+
+               d_index = new SourceIndex<Diagnostic>();
+               d_tags = new DiagnosticTags(d_view.view);
+               d_diagnostics_at_end = new Gee.HashMap<Gtk.TextMark, Gdk.RGBA?>();
+
+               register_marks();
+
+               var v = d_view.view;
+
+               v.set_show_line_marks(true);
+               v.query_tooltip.connect(on_view_query_tooltip);
+               v.draw.connect(on_view_draw);
+
+               var doc = d_view.document.document;
+               doc.mark_set.connect(on_buffer_mark_set);
+               doc.cursor_moved.connect(on_cursor_moved);
+       }
+
+       public void update(Diagnostic[] diagnostics)
+       {
+               d_index.clear();
+
+               foreach (var d in diagnostics)
+               {
+                       d_index.add(d);
+               }
+
+               update_scrollbar();
+               update_marks();
+       }
+
+       private void update_scrollbar()
+       {
+               var sm = d_view.scrollbar_marker;
+
+               if (sm == null)
+               {
+                       return;
+               }
+
+               sm.remove(d_last_marker_id);
+
+               var colors = new DiagnosticColors(sm.scrollbar.get_style_context());
+               var mixed = new DiagnosticColors(sm.scrollbar.get_style_context());
+
+               mixed.mix_in_widget(d_view.view);
+
+               var it = d_diagnostics_at_end.map_iterator();
+
+               var buf = d_view.view.buffer;
+
+               while (it.next())
+               {
+                       buf.delete_mark(it.get_key());
+               }
+
+               d_diagnostics_at_end.clear();
+
+               d_last_marker_id = sm.new_merge_id();
+
+               foreach (var d in d_index)
+               {
+                       Gdk.RGBA color = colors[d.severity];
+                       Gdk.RGBA mix = mixed[d.severity];
+
+                       foreach (SourceRange range in d.ranges)
+                       {
+                               sm.add_with_id(d_last_marker_id, range, color);
+
+                               if (range.start.line == range.end.line &&
+                                       range.start.column == range.end.column)
+                               {
+                                       if (diagnostic_is_at_end(range.start))
+                                       {
+                                               add_diagnostic_at_end(range.start, mix);
+                                       }
+                               }
+                       }
+               }
+
+               update_diagnostic_message();
+       }
+
+       private void update_marks()
+       {
+               Gtk.TextIter start;
+               Gtk.TextIter end;
+
+               var buf = d_view.view.buffer;
+
+               buf.get_bounds(out start, out end);
+
+               buf.remove_tag(d_tags.error_tag, start, end);
+               buf.remove_tag(d_tags.warning_tag, start, end);
+               buf.remove_tag(d_tags.info_tag, start, end);
+               buf.remove_tag(d_tags.fixit_tag, start, end);
+
+               remove_marks();
+
+               foreach (var d in d_index)
+               {
+                       mark_diagnostic(d);
+               }
+       }
+
+       private Diagnostic.Severity[] mark_severities()
+       {
+               return new Diagnostic.Severity[]{
+                       Diagnostic.Severity.ERROR,
+                       Diagnostic.Severity.WARNING,
+                       Diagnostic.Severity.INFO
+               };
+       }
+
+       private void register_marks()
+       {
+               foreach (var sev in mark_severities())
+               {
+                       var attr = new Gtk.SourceMarkAttributes();
+
+                       attr.set_gicon(new ThemedIcon.with_default_fallbacks(icon_name_for_severity(sev)));
+                       attr.query_tooltip_markup.connect(on_diagnostic_tooltip);
+
+                       d_view.view.set_mark_attributes(mark_category_for_severity(sev), attr, 0);
+               }
+       }
+
+       private void unregister_marks()
+       {
+               foreach (var sev in mark_severities())
+               {
+                       var attr = new Gtk.SourceMarkAttributes();
+                       d_view.view.set_mark_attributes(mark_category_for_severity(sev), attr, 0);
+               }
+       }
+
+       public void destroy()
+       {
+               if (d_view == null)
+               {
+                       return;
+               }
+
+               remove_marks();
+               unregister_marks();
+
+               var view = d_view.view;
+               view.set_show_line_marks(false);
+               view.query_tooltip.disconnect(on_view_query_tooltip);
+               view.draw.disconnect(on_view_draw);
+
+               var doc = d_view.document.document;
+               doc.mark_set.disconnect(on_buffer_mark_set);
+               doc.cursor_moved.disconnect(on_cursor_moved);
+
+               d_view = null;
+       }
+
+       private void remove_marks()
+       {
+               if (d_view == null)
+               {
+                       return;
+               }
+
+               Gtk.TextIter start;
+               Gtk.TextIter end;
+
+               var buf = d_view.document.document;
+
+               buf.get_bounds(out start, out end);
+               buf.remove_source_marks(start, end, info_mark_category);
+
+               buf.get_bounds(out start, out end);
+               buf.remove_source_marks(start, end, warning_mark_category);
+
+               buf.get_bounds(out start, out end);
+               buf.remove_source_marks(start, end, error_mark_category);
+       }
+
+       public static string? mark_category_for_severity(Diagnostic.Severity severity)
+       {
+               switch (severity)
+               {
+                       case Diagnostic.Severity.WARNING:
+                       case Diagnostic.Severity.DEPRECATED:
+                               return warning_mark_category;
+                       case Diagnostic.Severity.ERROR:
+                       case Diagnostic.Severity.FATAL:
+                               return error_mark_category;
+                       case Diagnostic.Severity.INFO:
+                               return info_mark_category;
+                       default:
+                               return null;
+               }
+       }
+
+       public static string? icon_name_for_severity(Diagnostic.Severity severity)
+       {
+               switch (severity)
+               {
+                       case Diagnostic.Severity.WARNING:
+                       case Diagnostic.Severity.DEPRECATED:
+                               return warning_icon_name;
+                       case Diagnostic.Severity.ERROR:
+                       case Diagnostic.Severity.FATAL:
+                               return error_icon_name;
+                       case Diagnostic.Severity.INFO:
+                               return info_icon_name;
+                       default:
+                               return null;
+               }
+       }
+
+       private Diagnostic[] sorted_on_severity(Diagnostic[] diagnostics)
+       {
+               var lst = new Gee.ArrayList<Diagnostic>.wrap(diagnostics);
+
+               lst.sort((a, b) => {
+                       if (a.severity == b.severity)
+                       {
+                               return 0;
+                       }
+
+                       // Higer priorities last
+                       return a.severity < b.severity ? -1 : 1;
+               });
+
+               return lst.to_array();
+       }
+
+       private Diagnostic[] find_at(SourceRange range)
+       {
+               return sorted_on_severity(d_index.find_at(range));
+       }
+
+       private Diagnostic[] find_at_line(int line)
+       {
+               return sorted_on_severity(d_index.find_at_line(line));
+       }
+
+       private void mark_diagnostic_range(Diagnostic   diagnostic,
+                                          Gtk.TextIter start,
+                                          Gtk.TextIter end)
+       {
+               Gtk.TextTag? tag = d_tags[diagnostic.severity];
+               string? category = mark_category_for_severity(diagnostic.severity);
+
+               var doc = d_view.document.document;
+
+               doc.apply_tag(tag, start, end);
+
+               Gtk.TextIter m = start;
+
+               if (!m.starts_line())
+               {
+                       m.set_line_offset(0);
+               }
+
+               while (category != null && m.compare(end) <= 0)
+               {
+                       bool alreadyhas = false;
+
+                       foreach (var mark in doc.get_source_marks_at_iter(m, category))
+                       {
+                               if (mark.get_data<Diagnostic>("Gca.Document.MarkDiagnostic") == diagnostic)
+                               {
+                                       alreadyhas = true;
+                                       break;
+                               }
+                       }
+
+                       if (!alreadyhas)
+                       {
+                               var mark = doc.create_source_mark(null, category, m);
+
+                               mark.set_data("Gca.Document.MarkDiagnostic", diagnostic);
+                       }
+
+                       if (!m.forward_line())
+                       {
+                               break;
+                       }
+               }
+       }
+
+       private void mark_diagnostic(Diagnostic diagnostic)
+       {
+               Gtk.TextIter start;
+               Gtk.TextIter end;
+
+               var doc = d_view.document.document;
+
+               for (uint i = 0; i < diagnostic.ranges.length; ++i)
+               {
+                       if (!diagnostic.ranges[i].get_iters(doc, out start, out end))
+                       {
+                               continue;
+                       }
+
+                       mark_diagnostic_range(diagnostic, start, end);
+               }
+
+               for (uint i = 0; i < diagnostic.fixits.length; ++i)
+               {
+                       SourceRange r = diagnostic.fixits[i].range;
+
+                       if (r.get_iters(doc, out start, out end))
+                       {
+                               doc.apply_tag(d_tags.fixit_tag, start, end);
+                       }
+               }
+       }
+
+       private bool diagnostic_is_at_end(SourceLocation location)
+       {
+               Gtk.TextIter iter;
+
+               d_view.view.buffer.get_iter_at_line(out iter, location.line - 1);
+               iter.forward_chars(location.column - 1);
+
+               if (iter.get_line() != location.line - 1)
+               {
+                       return false;
+               }
+
+               return iter.ends_line();
+       }
+
+       private void add_diagnostic_at_end(SourceLocation location,
+                                          Gdk.RGBA       color)
+       {
+               Gtk.TextIter iter;
+
+               d_view.view.buffer.get_iter_at_line(out iter, location.line - 1);
+
+               var mark = d_view.view.buffer.create_mark(null, iter, false);
+               d_diagnostics_at_end[mark] = color;
+       }
+
+       private bool on_view_draw(Cairo.Context ctx)
+       {
+               if (d_diagnostics_at_end.size == 0)
+               {
+                       return false;
+               }
+
+               var view = d_view.view;
+
+               var window = view.get_window(Gtk.TextWindowType.TEXT);
+
+               if (!Gtk.cairo_should_draw_window(ctx, window))
+               {
+                       return false;
+               }
+
+               var it = d_diagnostics_at_end.map_iterator();
+
+               Gtk.cairo_transform_to_window(ctx, view, window);
+               Gdk.Rectangle rect;
+               Gtk.TextIter start;
+               Gtk.TextIter end;
+
+               view.get_visible_rect(out rect);
+               view.get_line_at_y(out start, rect.y, null);
+               start.backward_line();
+
+               view.get_line_at_y(out end, rect.y + rect.height, null);
+               end.forward_line();
+
+               int window_width = window.get_width();
+
+               var buf = view.buffer;
+
+               while (it.next())
+               {
+                       Gtk.TextIter iter;
+
+                       buf.get_iter_at_mark(out iter, it.get_key());
+
+                       if (!iter.in_range(start, end) && !iter.equal(end))
+                       {
+                               continue;
+                       }
+
+                       if (!iter.ends_line())
+                       {
+                               if (iter.forward_visible_line())
+                               {
+                                       iter.backward_char();
+                               }
+                       }
+
+                       int y;
+                       int height;
+
+                       int wy;
+                       int wx;
+
+                       Gdk.Rectangle irect;
+
+                       view.get_line_yrange(iter, out y, out height);
+                       view.get_iter_location(iter, out irect);
+
+                       view.buffer_to_window_coords(Gtk.TextWindowType.TEXT,
+                                                    irect.x + irect.width,
+                                                    y,
+                                                    out wx,
+                                                    out wy);
+
+                       ctx.rectangle(wx,
+                                     wy,
+                                     window_width - wx,
+                                     height);
+
+                       Gdk.cairo_set_source_rgba(ctx, it.get_value());
+                       ctx.fill();
+               }
+
+               return false;
+       }
+
+       private void on_buffer_mark_set(Gtk.TextIter location, Gtk.TextMark mark)
+       {
+               if (d_diagnostics_at_end.has_key(mark) && !location.starts_line())
+               {
+                       location.set_line_offset(0);
+                       d_view.view.buffer.move_mark(mark, location);
+               }
+       }
+
+       private bool same_diagnostics(Diagnostic[]? first, Diagnostic[]? second)
+       {
+               if (first == second)
+               {
+                       return true;
+               }
+
+               if (first == null || second == null)
+               {
+                       return false;
+               }
+
+               if (first.length != second.length)
+               {
+                       return false;
+               }
+
+               for (int i = 0; i < first.length; ++i)
+               {
+                       if (first[i] != second[i])
+                       {
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+
+       private void update_diagnostic_message()
+       {
+               Gtk.TextIter iter;
+
+               var buf = d_view.view.buffer;
+
+               buf.get_iter_at_mark(out iter, buf.get_insert());
+
+               var range = SourceRange.from_iter(iter);
+               var diagnostics = find_at(range);
+
+               if (same_diagnostics(diagnostics, d_cursor_diagnostics))
+               {
+                       return;
+               }
+
+               if (d_cursor_diagnostic_message != null)
+               {
+                       d_cursor_diagnostic_message.destroy();
+               }
+
+               d_cursor_diagnostic_message = new DiagnosticMessage(d_view.view, diagnostics);
+
+               d_cursor_diagnostic_message.destroy.connect(() => {
+                       d_cursor_diagnostic_message = null;
+               });
+
+               d_cursor_diagnostic_message.show();
+               d_cursor_diagnostics = diagnostics;
+       }
+
+       private void on_cursor_moved()
+       {
+               update_diagnostic_message();
+       }
+
+       // Tooltips
+       private string? format_diagnostics(Diagnostic[] diagnostics)
+       {
+               if (diagnostics.length == 0)
+               {
+                       return null;
+               }
+
+               string[] markup = new string[diagnostics.length];
+
+               for (int i = 0; i < diagnostics.length; ++i)
+               {
+                       markup[i] = diagnostics[i].to_markup(false);
+               }
+
+               return string.joinv("\n", markup);
+       }
+
+       private string on_diagnostic_tooltip(Gtk.SourceMark mark)
+       {
+               Gtk.TextIter iter;
+
+               Diagnostic? diagnostic = mark.get_data("Gca.Document.MarkDiagnostic");
+
+               if (diagnostic == null)
+               {
+                       d_view.document.document.get_iter_at_mark(out iter, mark);
+                       int line = iter.get_line() + 1;
+
+                       return format_diagnostics(find_at_line(line));
+               }
+               else
+               {
+                       return diagnostic.to_markup(false);
+               }
+       }
+
+       private bool on_view_query_tooltip(int         x,
+                                          int         y,
+                                          bool        keyboard_mode,
+                                          Gtk.Tooltip tooltip)
+       {
+               int bx;
+               int by;
+
+               d_view.view.window_to_buffer_coords(Gtk.TextWindowType.WIDGET,
+                                                   x,
+                                                   y,
+                                                   out bx,
+                                                   out by);
+
+               Gtk.TextIter iter;
+       
+               d_view.view.get_iter_at_location(out iter, bx, by);
+
+               var range = SourceRange.from_iter(iter);
+
+               string? s = format_diagnostics(find_at(range));
+
+               if (s == null)
+               {
+                       return false;
+               }
+
+               tooltip.set_markup(s);
+               return true;
+       }
+}
+
+}
+
+/* vi:ex:ts=4 */
diff --git a/src/gca-document.vala b/src/gca-document.vala
new file mode 100644
index 0000000..6eb6cce
--- /dev/null
+++ b/src/gca-document.vala
@@ -0,0 +1,296 @@
+/*
+ * This file is part of gedit-code-assistant.
+ *
+ * Copyright (C) 2011 - Jesse van den Kieboom
+ *
+ * gedit-code-assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit-code-assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Gtk;
+
+namespace Gca
+{
+
+public class Document : Object
+{
+       private Gedit.Document d_document;
+
+       private bool d_untitled;
+       private bool d_modified;
+       private string? d_text;
+       private File? d_location;
+       private bool d_dispose_ran;
+
+       private File? d_unsaved_file;
+
+       public signal void location_changed(File? previous_location);
+       public signal void changed();
+
+       public Gedit.Document document
+       {
+               get { return d_document; }
+       }
+
+       public Document(Gedit.Document document)
+       {
+               d_document = document;
+
+               d_untitled = d_document.is_untitled();
+               d_modified = false;
+               d_text = null;
+
+               update_modified();
+
+               d_document.modified_changed.connect(on_document_modified_changed);
+               d_document.end_user_action.connect(on_document_end_user_action);
+               d_document.notify["location"].connect(on_location_changed);
+               d_document.saved.connect(on_document_saved);
+
+               d_location = null;
+
+               update_location();
+       }
+
+       public override void dispose()
+       {
+               if (!d_dispose_ran)
+               {
+                       d_dispose_ran = true;
+
+                       d_document.modified_changed.disconnect(on_document_modified_changed);
+                       d_document.notify["location"].disconnect(on_location_changed);
+
+                       d_document.end_user_action.disconnect(on_document_end_user_action);
+                       d_document.saved.disconnect(on_document_saved);
+
+                       clear_unsaved_file();
+               }
+
+               base.dispose();
+       }
+
+       private void set_location(File? location)
+       {
+               if (location == d_location)
+               {
+                       return;
+               }
+
+               File? prev = d_location;
+               d_location = location;
+
+               if ((prev == null) != (d_location == null))
+               {
+                       location_changed(prev);
+               }
+               else if (prev != null && !prev.equal(d_location))
+               {
+                       location_changed(prev);
+               }
+       }
+
+       private void update_location()
+       {
+               if (document.is_untitled())
+               {
+                       set_location(null);
+                       return;
+               }
+
+               if (!document.is_local())
+               {
+                       set_location(null);
+                       return;
+               }
+
+               set_location(document.location);
+       }
+
+       private void update_modified()
+       {
+               if (d_modified == d_document.get_modified())
+               {
+                       return;
+               }
+
+               d_text = null;
+               d_modified = !d_modified;
+
+               if (d_modified)
+               {
+                       update_text();
+               }
+               else
+               {
+                       emit_changed();
+               }
+       }
+
+       protected void emit_changed()
+       {
+               changed();
+       }
+
+       private void clear_unsaved_file()
+       {
+               if (d_unsaved_file != null)
+               {
+                       try
+                       {
+                               d_unsaved_file.delete();
+                       } catch {}
+
+                       d_unsaved_file = null;
+               }
+       }
+
+       private void update_text()
+       {
+               TextIter start;
+               TextIter end;
+
+               d_document.get_bounds(out start, out end);
+               d_text = d_document.get_text(start, end, true);
+
+               clear_unsaved_file();
+
+               emit_changed();
+       }
+
+       public File? location
+       {
+               get { return d_location; }
+       }
+
+       public unowned string text
+       {
+               get { return d_text; }
+       }
+
+       public bool is_modified
+       {
+               get { return d_modified; }
+       }
+
+       public int64 cursor
+       {
+               get
+               {
+                       var mark = d_document.get_insert();
+                       Gtk.TextIter iter;
+
+                       d_document.get_iter_at_mark(out iter, mark);
+
+                       return iter.get_offset();
+               }
+       }
+
+       public string path
+       {
+               owned get
+               {
+                       if (d_location == null)
+                       {
+                               return d_document.shortname;
+                       }
+                       else
+                       {
+                               return d_location.get_path();
+                       }
+               }
+       }
+
+       public async string? unsaved_data_path() throws IOError, Error
+       {
+               if (!d_modified)
+               {
+                       return null;
+               }
+
+               if (d_unsaved_file != null)
+               {
+                       return d_unsaved_file.get_path();
+               }
+
+               var orig = path;
+               var idx = orig.last_index_of(".");
+               string filename;
+
+               if (idx != -1)
+               {
+                       filename = "gca-unsaved-XXXXXX.%s".printf(orig[idx+1:orig.length]);
+               }
+               else
+               {
+                       filename = "gca-unsaved-XXXXXX";
+               }
+
+               FileIOStream stream;
+               File f;
+
+               f = File.new_tmp(filename, out stream);
+               var ostream = stream.output_stream;
+
+               try
+               {
+                       yield ostream.write_async(d_text.data);
+               }
+               catch (IOError e)
+               {
+                       try
+                       {
+                               f.delete();
+                       } catch {}
+
+                       try
+                       {
+                               ostream.close();
+                       } catch {}
+
+                       throw e;
+               }
+
+               ostream.close();
+               d_unsaved_file = f;
+
+               return d_unsaved_file.get_path();
+       }
+
+       private void on_document_end_user_action()
+       {
+               if (d_modified)
+               {
+                       update_text();
+               }
+       }
+
+       private void on_document_modified_changed()
+       {
+               update_modified();
+       }
+
+       private void on_location_changed()
+       {
+               update_location();
+       }
+
+       private void on_document_saved()
+       {
+               emit_changed();
+       }
+}
+
+}
+
+/* vi:ex:ts=4 */
diff --git a/src/gcp-expand-range.vala b/src/gca-expand-range.vala
similarity index 98%
rename from src/gcp-expand-range.vala
rename to src/gca-expand-range.vala
index f2e7e32..220d47d 100644
--- a/src/gcp-expand-range.vala
+++ b/src/gca-expand-range.vala
@@ -17,7 +17,7 @@
  * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-namespace Gcp
+namespace Gca
 {
 
 class ExpandRange
diff --git a/src/gcp-log.vala b/src/gca-log.vala
similarity index 96%
rename from src/gcp-log.vala
rename to src/gca-log.vala
index c22b9e6..945ec20 100644
--- a/src/gcp-log.vala
+++ b/src/gca-log.vala
@@ -1,8 +1,8 @@
-namespace Gcp
+namespace Gca
 {
        public class Log
        {
-               private static string Domain = "Gcp";
+               const string Domain = "Gca";
 
                [Diagnostics]
                [PrintfFormat]
diff --git a/src/gcp-plugin.vala b/src/gca-plugin.vala
similarity index 73%
rename from src/gcp-plugin.vala
rename to src/gca-plugin.vala
index d7bfa1b..95b63c9 100644
--- a/src/gcp-plugin.vala
+++ b/src/gca-plugin.vala
@@ -17,13 +17,14 @@
  * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-internal void peas_register_types (TypeModule module)
+//[ModuleInit]
+public static void peas_register_types(TypeModule module)
 {
        Peas.ObjectModule mod = module as Peas.ObjectModule;
 
-       mod.register_extension_type (typeof (Gedit.ViewActivatable),
-                                    typeof (Gcp.ViewActivatable));
+       mod.register_extension_type(typeof(Gedit.ViewActivatable),
+                                   typeof(Gca.ViewActivatable));
 
-       mod.register_extension_type (typeof (Gedit.AppActivatable),
-                                    typeof (Gcp.AppActivatable));
+       mod.register_extension_type(typeof(Gedit.AppActivatable),
+                                   typeof(Gca.AppActivatable));
 }
diff --git a/src/gca-remote-service.vala b/src/gca-remote-service.vala
new file mode 100644
index 0000000..dc98fdd
--- /dev/null
+++ b/src/gca-remote-service.vala
@@ -0,0 +1,81 @@
+/*
+ * This file is part of gedit-code-assistant.
+ *
+ * Copyright (C) 2013 - Jesse van den Kieboom
+ *
+ * gedit-code-assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit-code-assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Gca
+{
+
+[Flags]
+enum RemoteServices
+{
+       DIAGNOSTICS,
+       SEMANTIC_VALUES,
+       SYMBOLS,
+       MULTI_DOC;
+
+       public static RemoteServices parse(string s)
+       {
+               switch (s)
+               {
+               case "org.gnome.CodeAssist.Diagnostics":
+                       return RemoteServices.DIAGNOSTICS;
+               case "org.gnome.CodeAssist.SemanticValues":
+                       return RemoteServices.SEMANTIC_VALUES;
+               case "org.gnome.CodeAssist.Symbols":
+                       return RemoteServices.SYMBOLS;
+               case "org.gnome.CodeAssist.MultiDoc":
+                       return RemoteServices.MULTI_DOC;
+               }
+
+               return 0;
+       }
+}
+
+
+class RemoteDocument
+{
+       private string d_service;
+       private ObjectPath d_path;
+
+       public RemoteDocument(string service, ObjectPath path)
+       {
+               d_service = service;
+               d_path = path;
+       }
+
+       public async T get_proxy<T>() throws IOError
+       {
+               return yield Bus.get_proxy<T>(BusType.SESSION, d_service, d_path);
+       }
+
+       public ObjectPath path
+       {
+               get { return d_path; }
+       }
+}
+
+interface RemoteService : Object
+{
+       public abstract RemoteServices services();
+       public abstract void update(View view, RemoteDocument document);
+       public abstract void destroy();
+}
+
+}
+
+/* vi:ex:ts=4 */
diff --git a/src/gcp-scrollbar-marker.vala b/src/gca-scrollbar-marker.vala
similarity index 86%
rename from src/gcp-scrollbar-marker.vala
rename to src/gca-scrollbar-marker.vala
index 54413b3..85137e6 100644
--- a/src/gcp-scrollbar-marker.vala
+++ b/src/gca-scrollbar-marker.vala
@@ -20,12 +20,12 @@
 using Gtk;
 using Gee;
 
-namespace Gcp
+namespace Gca
 {
 
-public class ScrollbarMarker
+class ScrollbarMarker
 {
-       public class Marker
+       class Marker
        {
                private Gdk.RGBA d_color;
                private SourceRange d_range;
@@ -93,14 +93,14 @@ public class ScrollbarMarker
        {
                StyleContext ctx = d_scrollbar.get_style_context();
 
-               int stepper_size = GcpUtilsC.get_style_property_int(ctx,
+               int stepper_size = GcaUtilsC.get_style_property_int(ctx,
                                                                 "stepper-size");
 
-               int stepper_spacing = GcpUtilsC.get_style_property_int(ctx,
+               int stepper_spacing = GcaUtilsC.get_style_property_int(ctx,
                                                                    "stepper-spacing");
 
-               d_border = GcpUtilsC.get_style_property_int(ctx, "trough-border");
-               d_width = GcpUtilsC.get_style_property_int(ctx, "slider-width");
+               d_border = GcaUtilsC.get_style_property_int(ctx, "trough-border");
+               d_width = GcaUtilsC.get_style_property_int(ctx, "slider-width");
 
                d_spacing = stepper_size + stepper_spacing + 2;
        }
@@ -135,14 +135,6 @@ public class ScrollbarMarker
                d_scrollbar.queue_draw();
        }
 
-       public uint add(SourceRange range, Gdk.RGBA color)
-       {
-               uint id = new_merge_id();
-
-               add_with_id(id, range, color);
-               return id;
-       }
-
        public void remove(uint id)
        {
                if (!d_markers.has_key(id))
@@ -154,14 +146,6 @@ public class ScrollbarMarker
                d_scrollbar.queue_draw();
        }
 
-       public void clear()
-       {
-               d_markers.clear();
-               d_mergeId = 0;
-
-               d_scrollbar.queue_draw();
-       }
-
        ~ScrollbarMarker()
        {
                if (d_scrollbar == null)
@@ -203,9 +187,8 @@ public class ScrollbarMarker
 
        private bool on_scrollbar_draw(Cairo.Context ctx)
        {
-               Gdk.Rectangle range;
-
-               d_scrollbar.get_range_rect(out range);
+               // TODO: check
+               var range = GcaUtilsC.get_range_rect(d_scrollbar);
 
                // Remove stepper button sizes
                range.x += d_border;
diff --git a/src/gcp-semantic-value-support.vala b/src/gca-semantic-value-support.vala
similarity index 68%
rename from src/gcp-semantic-value-support.vala
rename to src/gca-semantic-value-support.vala
index f659f6b..2508846 100644
--- a/src/gcp-semantic-value-support.vala
+++ b/src/gca-semantic-value-support.vala
@@ -1,9 +1,9 @@
-namespace Gcp
+namespace Gca
 {
 
-public delegate void WithSemanticValueCallback(SourceIndex diagnostics);
+delegate void WithSemanticValueCallback(SourceIndex diagnostics);
 
-public interface SemanticValueSupport : Gcp.Document
+interface SemanticValueSupport : Gca.Document
 {
        public void with_semantics(WithSemanticValueCallback callback)
        {
diff --git a/src/gcp-semantic-value.vala b/src/gca-semantic-value.vala
similarity index 94%
rename from src/gcp-semantic-value.vala
rename to src/gca-semantic-value.vala
index 55873c1..4f8b178 100644
--- a/src/gcp-semantic-value.vala
+++ b/src/gca-semantic-value.vala
@@ -1,7 +1,7 @@
-namespace Gcp
+namespace Gca
 {
 
-public abstract class SemanticValue : Object, SourceRangeSupport
+abstract class SemanticValue : Object, SourceRangeSupport
 {
        public enum Kind
        {
diff --git a/src/gcp-source-index.vala b/src/gca-source-index.vala
similarity index 54%
rename from src/gcp-source-index.vala
rename to src/gca-source-index.vala
index be15e6e..6887af6 100644
--- a/src/gcp-source-index.vala
+++ b/src/gca-source-index.vala
@@ -19,19 +19,19 @@
 
 using Gee;
 
-namespace Gcp
+namespace Gca
 {
 
-public class SourceIndex : Object
+class SourceIndex<T> : Object
 {
        public class Wrapper : Object
        {
-               public SourceRangeSupport obj;
+               public SourceRangeSupport? obj;
                public SourceRange range;
                public int idx;
                public bool encapsulated;
 
-               public Wrapper(SourceRangeSupport obj, SourceRange range, int idx)
+               public Wrapper(SourceRangeSupport? obj, SourceRange range, int idx)
                {
                        this.obj = obj;
                        this.range = range;
@@ -41,7 +41,7 @@ public class SourceIndex : Object
                }
        }
 
-       public class Iterator : Object
+       public class Iterator<T> : Object
        {
                private SequenceIter<Wrapper> d_iter;
                private bool d_first;
@@ -66,9 +66,9 @@ public class SourceIndex : Object
                        return !d_iter.is_end();
                }
 
-               public new Object get()
+               public new T get()
                {
-                       return d_iter.get().obj;
+                       return (T)d_iter.get().obj;
                }
        }
 
@@ -114,7 +114,7 @@ public class SourceIndex : Object
                                }
                        }
 
-                       d_index.insert_before(iter, wrapper);
+                       iter = Sequence<Wrapper>.insert_before(iter, wrapper);
 
                        while (!iter.is_end() && wrapper.range.contains_range(iter.get().range))
                        {
@@ -124,58 +124,11 @@ public class SourceIndex : Object
                });
        }
 
-       public new Object? get(int idx)
-       {
-               SequenceIter<Wrapper>? iter = d_index.get_iter_at_pos(idx);
-
-               if (iter == null)
-               {
-                       return null;
-               }
-
-               return iter.get().obj;
-       }
-
        public int length
        {
                get { return d_index.get_length(); }
        }
 
-       private SequenceIter<Wrapper>? find_iter(Wrapper wrapper)
-       {
-               SequenceIter<Wrapper>? iter;
-
-               iter = d_index.search(wrapper, compare_func);
-
-               if (iter == null)
-               {
-                       return null;
-               }
-
-               // Move back on same
-               while (!iter.is_begin())
-               {
-                       SequenceIter<Wrapper> prev = iter.prev();
-
-                       if (prev.get().range.compare_to(wrapper.range) != 0)
-                       {
-                               break;
-                       }
-
-                       iter = prev;
-               }
-
-               // Move forward until find, or end, or not same
-               while (!iter.is_end() &&
-                      iter.get().range.compare_to(wrapper.range) == 0 &&
-                      iter.get().obj != wrapper.obj)
-               {
-                       iter = iter.next();
-               }
-
-               return iter.get().obj == wrapper.obj ? iter : null;
-       }
-
        private delegate void WrapEachFunc(Wrapper wrapper);
 
        private void wrap_each(SourceRangeSupport range, WrapEachFunc func)
@@ -188,63 +141,47 @@ public class SourceIndex : Object
                }
        }
 
-       public void remove(SourceRangeSupport range)
+       public T[] find_at_line(int line)
        {
-               wrap_each(range, (wrapper) => {
-                       SequenceIter<Wrapper>? iter;
-
-                       iter = find_iter(wrapper);
-
-                       if (iter != null)
-                       {
-                               d_index.remove(iter);
-                       }
-               });
-       }
+               var loc = SourceLocation() {
+                       line = line,
+                       column = 0
+               };
 
-       public Object[] find_at_line(int line)
-       {
-               return find_at_priv(new SourceLocation(null, line, 0), FindFlags.LINE_ONLY);
+               return find_at_priv(loc.to_range(), FindFlags.LINE_ONLY);
        }
 
-       public Object[] find_at(SourceLocation location)
+       public T[] find_at(SourceRange range)
        {
-               return find_at_priv(location, FindFlags.NONE);
+               return find_at_priv(range, FindFlags.NONE);
        }
 
-       public Object? find_inner_at(SourceLocation location)
+       private bool find_at_condition(Wrapper     wrapper,
+                                      SourceRange range,
+                                      FindFlags   flags)
        {
-               Object[] ret = find_at_priv(location, FindFlags.INNER_MOST);
+               bool lineonly = (flags & FindFlags.LINE_ONLY) != 0;
 
-               if (ret.length == 0)
+               if (lineonly)
                {
-                       return null;
+                       return wrapper.range.contains_line(range.start.line) &&
+                              wrapper.range.contains_line(range.end.line);
                }
                else
                {
-                       return (owned)ret[0];
+                       return wrapper.range.contains_range(range);
                }
        }
 
-       private bool find_at_condition(Wrapper wrapper,
-                                      SourceLocation location,
-                                      FindFlags flags)
-       {
-               bool lineonly = (flags & FindFlags.LINE_ONLY) != 0;
-
-               return (lineonly && wrapper.range.contains_line(location.line)) ||
-                      (!lineonly && wrapper.range.contains_location(location));
-       }
-
-       private Object[] find_at_priv(SourceLocation location,
-                                FindFlags flags)
+       private T[] find_at_priv(SourceRange range,
+                                FindFlags   flags)
        {
-               LinkedList<Object> ret = new LinkedList<Object>();
+               LinkedList<T> ret = new LinkedList<Object>();
 
                SequenceIter<Wrapper> iter;
-               HashMap<Object, bool> uniq = new HashMap<Object, bool>(direct_hash, direct_equal);
+               var uniq = new HashMap<Object, bool>();
 
-               iter = d_index.search(new Wrapper(location, location.range, 0), compare_func);
+               iter = d_index.search(new Wrapper(null, range, 0), compare_func);
 
                if ((flags & FindFlags.INNER_MOST) != 0)
                {
@@ -252,9 +189,9 @@ public class SourceIndex : Object
                        {
                                iter = iter.prev();
 
-                               if (find_at_condition(iter.get(), location, flags))
+                               if (find_at_condition(iter.get(), range, flags))
                                {
-                                       return new Object[] {iter.get().obj};
+                                       return new T[] {(T)iter.get().obj};
                                }
                                else if (!iter.get().encapsulated)
                                {
@@ -262,7 +199,7 @@ public class SourceIndex : Object
                                }
                        }
 
-                       return new Object[] {};
+                       return new T[] {};
                }
 
                // Go back to find ranges that encapsulate the location
@@ -270,15 +207,15 @@ public class SourceIndex : Object
                {
                        SequenceIter<Wrapper> prev = iter.prev();
 
-                       while (find_at_condition(prev.get(), location, flags) ||
+                       while (find_at_condition(prev.get(), range, flags) ||
                               prev.get().encapsulated)
                        {
-                               Object val = (Object)prev.get().obj;
+                               var val = prev.get().obj;
 
-                               if (find_at_condition(prev.get(), location, flags) &&
+                               if (find_at_condition(prev.get(), range, flags) &&
                                    !uniq.has_key(val))
                                {
-                                       ret.insert(0, val);
+                                       ret.insert(0, (T)val);
                                        uniq[val] = true;
                                }
 
@@ -293,14 +230,14 @@ public class SourceIndex : Object
 
                // Then move with iter forward
                while (!iter.is_end() &&
-                      (find_at_condition(iter.get(), location, flags) ||
+                      (find_at_condition(iter.get(), range, flags) ||
                        iter.get().encapsulated))
                {
-                       Object val = (Object)iter.get().obj;
+                       var val = iter.get().obj;
 
-                       if (find_at_condition(iter.get(), location, flags) && !uniq.has_key(val))
+                       if (find_at_condition(iter.get(), range, flags) && !uniq.has_key(val))
                        {
-                               ret.add(val);
+                               ret.add((T)val);
                                uniq[val] = true;
                        }
 
@@ -312,7 +249,7 @@ public class SourceIndex : Object
 
        public void clear()
        {
-               d_index.remove_range(d_index.get_begin_iter(), d_index.get_end_iter());
+               Sequence<Wrapper>.remove_range(d_index.get_begin_iter(), d_index.get_end_iter());
        }
 
        private int compare_func(Wrapper a, Wrapper b)
@@ -323,9 +260,9 @@ public class SourceIndex : Object
                return ra.compare_to(rb);
        }
 
-       public Iterator iterator()
+       public Iterator<T> iterator()
        {
-               return new Iterator(d_index.get_begin_iter());
+               return new Iterator<T>(d_index.get_begin_iter());
        }
 }
 
diff --git a/src/gcp-source-location.vala b/src/gca-source-location.vala
similarity index 57%
rename from src/gcp-source-location.vala
rename to src/gca-source-location.vala
index 72cb4f7..15b9db8 100644
--- a/src/gcp-source-location.vala
+++ b/src/gca-source-location.vala
@@ -19,62 +19,37 @@
 
 using Gtk;
 
-namespace Gcp
+namespace Gca
 {
 
-public class SourceLocation : Object, SourceRangeSupport
+struct SourceLocation
 {
-       private File? d_file;
-       private int d_line;
-       private int d_column;
+//     public File? file;
+       public int line;
+       public int column;
 
-       public SourceLocation(File? file, int line, int column)
+       public static SourceLocation from_iter(TextIter iter)
        {
-               d_file = file;
-               d_line = line;
-               d_column = column;
+               return SourceLocation() {
+                       line = iter.get_line() + 1,
+                       column = iter.get_line_offset() + 1
+               };
        }
 
-       public SourceLocation.iter(TextIter iter)
+       public static SourceLocation from_dbus(DBus.SourceLocation location)
        {
-               this(null, iter.get_line() + 1, iter.get_line_offset() + 1);
+               return Gca.SourceLocation() {
+                       line = (int)location.line,
+                       column = (int)location.column
+               };
        }
 
-       public SourceLocation copy()
+       public SourceRange to_range()
        {
-               return new SourceLocation(d_file.dup(), d_line, d_column);
-       }
-
-       public File? file
-       {
-               get { return d_file; }
-       }
-
-       public int line
-       {
-               get { return d_line; }
-               set { d_line = value; }
-       }
-
-       public int column
-       {
-               get { return d_column; }
-       }
-
-       public SourceRange? range
-       {
-               owned get
-               {
-                       SourceRange r = new SourceRange(new SourceLocation(d_file, d_line, d_column),
-                                                       new SourceLocation(d_file, d_line, d_column));
-
-                       return (owned)r;
-               }
-       }
-
-       public SourceRange[] ranges
-       {
-               owned get { return new SourceRange[] {range}; }
+               return SourceRange() {
+                       start = this,
+                       end = this
+               };
        }
 
        private int compare_int(int a, int b)
@@ -84,21 +59,21 @@ public class SourceLocation : Object, SourceRangeSupport
 
        public int compare_to(SourceLocation other)
        {
-               if (d_line == other.d_line)
+               if (line == other.line)
                {
-                       return compare_int(d_column, other.d_column);
+                       return compare_int(column, other.column);
                }
                else
                {
-                       return d_line < other.d_line ? -1 : 1;
+                       return compare_int(line, other.line);
                }
        }
 
        public bool get_iter(TextBuffer buffer, out TextIter iter)
        {
-               buffer.get_iter_at_line(out iter, d_line - 1);
+               buffer.get_iter_at_line(out iter, line - 1);
 
-               if (iter.get_line() != d_line - 1)
+               if (iter.get_line() != line - 1)
                {
                        if (iter.is_end())
                        {
@@ -108,12 +83,12 @@ public class SourceLocation : Object, SourceRangeSupport
                        return false;
                }
 
-               if (d_column <= 1)
+               if (column <= 1)
                {
                        return true;
                }
 
-               bool ret = iter.forward_chars(d_column - 1);
+               bool ret = iter.forward_chars(column - 1);
 
                if (!ret && iter.is_end())
                {
diff --git a/src/gcp-source-range-support.vala b/src/gca-source-range-support.vala
similarity index 88%
rename from src/gcp-source-range-support.vala
rename to src/gca-source-range-support.vala
index c5a827c..a53333b 100644
--- a/src/gcp-source-range-support.vala
+++ b/src/gca-source-range-support.vala
@@ -16,16 +16,11 @@
  * You should have received a copy of the GNU General Public License
  * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
  */
-namespace Gcp
+namespace Gca
 {
 
-public interface SourceRangeSupport : Object
+interface SourceRangeSupport : Object
 {
-       public abstract SourceRange? range
-       {
-               owned get;
-       }
-
        public abstract SourceRange[] ranges
        {
                owned get;
diff --git a/src/gcp-source-range.vala b/src/gca-source-range.vala
similarity index 55%
rename from src/gcp-source-range.vala
rename to src/gca-source-range.vala
index 0f4a163..421cf43 100644
--- a/src/gcp-source-range.vala
+++ b/src/gca-source-range.vala
@@ -17,61 +17,53 @@
  * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-namespace Gcp
+namespace Gca
 {
 
-public class SourceRange : Object, SourceRangeSupport
+struct SourceRange
 {
-       private SourceLocation d_start;
-       private SourceLocation d_end;
+       public SourceLocation start;
+       public SourceLocation end;
 
-       public SourceRange(SourceLocation start, SourceLocation end)
+       public static SourceRange from_iter(Gtk.TextIter iter)
        {
-               d_start = start;
-               d_end = end;
-       }
-
-       public SourceRange? range
-       {
-               owned get { return this; }
-       }
+               var loc = SourceLocation.from_iter(iter);
 
-       public SourceRange[] ranges
-       {
-               owned get { return new SourceRange[] {this}; }
-       }
-
-       public SourceLocation start
-       {
-               get { return d_start; }
+               return SourceRange() {
+                       start = loc,
+                       end = loc
+               };
        }
 
-       public SourceLocation end
+       public static SourceRange from_dbus(DBus.SourceRange range)
        {
-               get { return d_end; }
+               return Gca.SourceRange() {
+                       start = SourceLocation.from_dbus(range.start),
+                       end = SourceLocation.from_dbus(range.end)
+               };
        }
 
        public int compare_to(SourceRange other)
        {
-               int st = d_start.compare_to(other.d_start);
+               int st = start.compare_to(other.start);
 
-               if (st != 0)
+               if (st == 0)
                {
-                       return st;
+                       st = other.end.compare_to(end);
                }
 
-               return other.d_end.compare_to(d_end);
+               return st;
        }
 
-       public bool get_iters(Gtk.TextBuffer buffer,
+       public bool get_iters(Gtk.TextBuffer   buffer,
                              out Gtk.TextIter start,
                              out Gtk.TextIter end)
        {
                bool rets;
                bool rete;
 
-               rets = d_start.get_iter(buffer, out start);
-               rete = d_end.get_iter(buffer, out end);
+               rets = this.start.get_iter(buffer, out start);
+               rete = this.end.get_iter(buffer, out end);
 
                return rets && rete;
        }
@@ -88,23 +80,23 @@ public class SourceRange : Object, SourceRangeSupport
 
        public bool contains(int line, int column)
        {
-               return (d_start.line < line || (d_start.line == line && d_start.column <= column)) &&
-                      (d_end.line > line || (d_end.line == line && d_end.column >= column));
+               return (start.line < line || (start.line == line && start.column <= column)) &&
+                      (end.line > line || (end.line == line && end.column >= column));
        }
 
        public bool contains_line(int line)
        {
-               return d_start.line <= line && d_end.line >= line;
+               return start.line <= line && end.line >= line;
        }
 
        public string to_string()
        {
-               if (d_start.line == d_end.line && d_end.column - d_start.column <= 1)
+               if (start.line == end.line && end.column - start.column <= 1)
                {
-                       return d_start.to_string();
+                       return start.to_string();
                }
 
-               return "%s-%s".printf(d_start.to_string(), d_end.to_string());
+               return "%s-%s".printf(start.to_string(), end.to_string());
        }
 }
 
diff --git a/src/gcp-symbol-browser-support.vala b/src/gca-symbol-browser-support.vala
similarity index 93%
rename from src/gcp-symbol-browser-support.vala
rename to src/gca-symbol-browser-support.vala
index 4423483..d878600 100644
--- a/src/gcp-symbol-browser-support.vala
+++ b/src/gca-symbol-browser-support.vala
@@ -17,13 +17,13 @@
  * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-namespace Gcp
+namespace Gca
 {
 
 /**
  * Interface for documents supporting symbol browsing
  *
- * This interface is implemented on a Gcp.Document when it supports symbol
+ * This interface is implemented on a Gca.Document when it supports symbol
  * browsing.
  *
  */
diff --git a/src/gcp-symbol-browser.vala b/src/gca-symbol-browser.vala
similarity index 98%
rename from src/gcp-symbol-browser.vala
rename to src/gca-symbol-browser.vala
index 96799cd..188fa85 100644
--- a/src/gcp-symbol-browser.vala
+++ b/src/gca-symbol-browser.vala
@@ -17,7 +17,7 @@
  * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-namespace Gcp
+namespace Gca
 {
 
 public class SymbolBrowser : Gtk.TreeStore
diff --git a/src/gcp-unsaved-file.vala b/src/gca-unsaved-file.vala
similarity index 98%
rename from src/gcp-unsaved-file.vala
rename to src/gca-unsaved-file.vala
index 1f718bf..e8119d3 100644
--- a/src/gcp-unsaved-file.vala
+++ b/src/gca-unsaved-file.vala
@@ -17,7 +17,7 @@
  * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-namespace Gcp
+namespace Gca
 {
 
 public struct UnsavedFile
diff --git a/src/gcp-view-activatable.vala b/src/gca-view-activatable.vala
similarity index 89%
rename from src/gcp-view-activatable.vala
rename to src/gca-view-activatable.vala
index 62fcab8..e730f79 100644
--- a/src/gcp-view-activatable.vala
+++ b/src/gca-view-activatable.vala
@@ -19,18 +19,18 @@
 
 using Gtk;
 
-namespace Gcp
+namespace Gca
 {
 
 class ViewActivatable : GLib.Object, Gedit.ViewActivatable
 {
-       public Gedit.View view {get; set;}
+       public Gedit.View view { construct; owned get; }
 
-       private Gcp.View d_view;
+       private Gca.View d_view;
 
        public void activate()
        {
-               d_view = new Gcp.View(view);
+               d_view = new Gca.View(view);
        }
 
        public void deactivate()
diff --git a/src/gca-view.vala b/src/gca-view.vala
new file mode 100644
index 0000000..5eb0c0d
--- /dev/null
+++ b/src/gca-view.vala
@@ -0,0 +1,211 @@
+/*
+ * This file is part of gedit-code-assistant.
+ *
+ * Copyright (C) 2011 - Jesse van den Kieboom
+ *
+ * gedit-code-assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit-code-assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit-code-assistant.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Gtk;
+using Gee;
+
+namespace Gca
+{
+
+/**
+ * Wrapper around Gedit.View.
+ *
+ * View is a wrapper around Gedit.View. It keeps track of changes to the document
+ * of the gedit view and of the language of the document and registers itself
+ * with the appropriate assistance backend.
+ */
+class View : Object
+{
+       private unowned Gedit.View d_view;
+       private Document d_document;
+       private Backend d_backend;
+       private ScrollbarMarker? d_scrollbar_marker;
+       private uint d_timeout;
+
+       private RemoteService[] d_services;
+
+       public signal void changed();
+
+       public View(Gedit.View view)
+       {
+               d_view = view;
+
+               d_view.notify["buffer"].connect(on_notify_buffer);
+
+               connect_document(d_view.buffer as Gedit.Document);
+
+               ScrolledWindow? sw = d_view.parent as ScrolledWindow;
+
+               if (sw != null)
+               {
+                       d_scrollbar_marker = new ScrollbarMarker(sw.get_vscrollbar() as Scrollbar);
+               }
+
+               d_services = new RemoteService[] {
+                       new DiagnosticService()
+               };
+       }
+
+       public unowned Gedit.View view
+       {
+               get { return d_view; }
+       }
+
+       public Document document
+       {
+               get { return d_document; }
+       }
+
+       public ScrollbarMarker? scrollbar_marker
+       {
+               get { return d_scrollbar_marker; }
+       }
+
+       public void deactivate()
+       {
+               d_view.notify["buffer"].disconnect(on_notify_buffer);
+
+               disconnect_document();
+
+               d_view = null;
+       }
+
+       public void update(RemoteDocument doc)
+       {
+               foreach (var service in d_services)
+               {
+                       if (d_backend.supports(service.services()))
+                       {
+                               service.update(this, doc);
+                       }
+               }
+       }
+
+       private void disconnect_document()
+       {
+               if (d_document == null)
+               {
+                       return;
+               }
+
+               var buf = d_document.document;
+
+               buf.notify["language"].disconnect(on_notify_language);
+               d_document.changed.disconnect(on_document_changed);
+
+               unregister_backend();
+
+               d_document = null;
+       }
+
+       private void connect_document(Gedit.Document? document)
+       {
+               disconnect_document();
+
+               if (document == null)
+               {
+                       return;
+               }
+
+               d_document = new Document(document);
+
+               var buf = d_document.document;
+
+               buf.notify["language"].connect(on_notify_language);
+
+               d_document.changed.connect(on_document_changed);
+               update_backend();
+       }
+
+       private void on_document_changed()
+       {
+               d_scrollbar_marker.max_line = d_document.document.get_line_count();
+
+               if (d_timeout != 0)
+               {
+                       Source.remove(d_timeout);
+               }
+
+               d_timeout = Timeout.add(200, () => {
+                       d_timeout = 0;
+                       changed();
+                       return false;
+               });
+       }
+
+       private void update_backend()
+       {
+               unregister_backend();
+
+               /* Update the backend according to the current language on the buffer */
+               if (d_document != null && d_document.document.language != null)
+               {
+                       var manager = BackendManager.instance;
+
+                       manager.backend.begin(d_document.document.language.id, (obj, res) => {
+                               var backend = manager.backend.end(res);
+                               register_backend(backend);
+                       });
+               }
+       }
+
+       private void unregister_backend()
+       {
+               if (d_backend == null)
+               {
+                       return;
+               }
+
+               foreach (var service in d_services)
+               {
+                       service.destroy();
+               }
+
+               d_backend.unregister(this);
+               d_backend = null;
+       }
+
+       private void register_backend(Backend? backend)
+       {
+               d_backend = backend;
+
+               if (backend == null)
+               {
+                       return;
+               }
+
+               backend.register(this);
+               on_document_changed();
+       }
+
+       private void on_notify_buffer()
+       {
+               disconnect_document();
+               connect_document(d_view.buffer as Gedit.Document);
+       }
+
+       private void on_notify_language()
+       {
+               update_backend();
+       }
+}
+
+}
+
+/* vi:ex:ts=4 */
diff --git a/vapi/Makefile.am b/vapi/Makefile.am
index 141a5ed..20fdf3e 100644
--- a/vapi/Makefile.am
+++ b/vapi/Makefile.am
@@ -1,15 +1,4 @@
-EXTRA_DIST = \
-       clang.vapi \
-       config.vapi \
-       gcp-utils.vapi \
-       gdk-3.0.deps \
-       gdk-3.0.vapi \
-       gedit-3.0.vapi \
-       gobject-introspection-1.0.vapi \
-       gtk+-3.0.deps \
-       gtk+-3.0.vapi \
-       gobject-introspection-1.0.vapi \
-       gtksourceview-3.0.vapi \
-       libpeas-1.0.vapi
+EXTRA_DIST +=                                  \
+       vapi/gca-utils.vapi
 
--include $(top_srcdir)/git.mk
+GITIGNOREDEPS += vapi/Makefile.am
diff --git a/vapi/gca-utils.vapi b/vapi/gca-utils.vapi
new file mode 100644
index 0000000..d009b4a
--- /dev/null
+++ b/vapi/gca-utils.vapi
@@ -0,0 +1,12 @@
+[CCode(lower_case_cprefix = "gca_utils_c", cheader_filename = "src/gca-utils-c.h")]
+namespace GcaUtilsC
+{
+       [CCode (cname = "gca_utils_c_get_style_property_int")]
+       public static int get_style_property_int(Gtk.StyleContext context,
+                                                string           name);
+
+       [CCode (cname = "gca_utils_c_get_range_rect")]
+       public static Gdk.Rectangle get_range_rect(Gtk.Range range);
+}
+
+/* vi:ex:ts=4 */



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