Commit 662cb09f authored by Daniel Espinosa Ortiz's avatar Daniel Espinosa Ortiz

sourceview: added syntax highlight basics

parent f2faec42
......@@ -21,37 +21,56 @@ public class GVls.GScanner : Object {
public signal void keyword (Symbol k);
private GLib.File _file = null;
private string _content = null;
public GLib.File file { get { return _file; } }
public string content { get { return _content; } }
public GScanner.with_file (GLib.File file) {
public GScanner.from_file (GLib.File file) {
_file = file;
}
public GScanner.from_string (string str) {
_content = str;
}
public void start () throws GLib.Error
requires (file != null)
{
var context = new CodeContext ();
CodeContext.push (context);
SourceFileType type = SourceFileType.NONE;
if (file.get_basename ().has_suffix (".vala")) {
if (file == null) {
type = SourceFileType.SOURCE;
}
if (file.get_basename ().has_suffix (".vapi")) {
type = SourceFileType.PACKAGE;
} else {
if (file.get_basename ().has_suffix (".vala")) {
type = SourceFileType.SOURCE;
}
if (file.get_basename ().has_suffix (".vapi")) {
type = SourceFileType.PACKAGE;
}
}
if (type == SourceFileType.NONE) {
throw new ScannerError.FILE_TYPE_ERROR ("File not supported");
throw new ScannerError.FILE_TYPE_ERROR ("File not supported: %s", file.get_uri ());
}
var filename = file.get_path ();
var sf = new SourceFile (context, type, filename);
string filename = "file:///stdin";
if (file != null) {
filename = file.get_path ();
}
if (file == null && content == null) {
throw new ScannerError.CONTENT_ERROR ("Content should not be null if no file is set");
}
var sf = new SourceFile (context, type, filename, content);
var scanner = new Vala.Scanner (sf);
// FIXME: Parse use parse_file_comments()
Vala.TokenType token = Vala.TokenType.NONE;
while (token != Vala.TokenType.EOF) {
Vala.SourceLocation begin, end;
token = scanner.read_token (out begin, out end);
var loc = new GLocation.from_values (file, begin.line, begin.column, end.line, end.column);
GLib.File f = file;
if (f == null) {
f = GLib.File.new_for_uri (filename);
}
var loc = new GLocation.from_values (f, begin.line - 1, begin.column - 1,
end.line - 1, end.column);
switch (token) {
case Vala.TokenType.ABSTRACT:
case Vala.TokenType.AS:
......@@ -202,5 +221,6 @@ public class GVls.GScanner : Object {
}
public errordomain GVls.ScannerError {
FILE_TYPE_ERROR
FILE_TYPE_ERROR,
CONTENT_ERROR
}
......@@ -22,12 +22,22 @@ public class GVls.GServer : GLib.Object, ContainerHashable, Server
{
private GVls.Container _servers = new GContainer () as GVls.Container;
private GLib.File _file;
private string _string;
private GVls.Container _symbols = new GContainer () as GVls.Container;
private Vala.SourceFile source = null;
private GVls.Container _vapi_dirs = new GContainer () as GVls.Container;
public GVls.Container servers { get { return _servers; } }
public GLib.File file { get { return _file; } }
public string content {
get {
return _string;
}
set {
_string = value;
parse_string (_string);
}
}
public GVls.Container symbols { get{ return _symbols; } }
public GLib.File prefix_dir { get; set; }
public GVls.Container vapi_dirs { get { return _vapi_dirs; } }
......@@ -35,6 +45,7 @@ public class GVls.GServer : GLib.Object, ContainerHashable, Server
construct {
prefix_dir = GLib.File.new_for_uri ("file://"+PREFIX+"/"+DATADIR);
_file = GLib.File.new_for_uri ("file:///@RootServer@/%s".printf (GLib.Uuid.string_random ()));
_string = "";
}
public void parse (GLib.File file) throws GLib.Error {
......@@ -164,7 +175,13 @@ public class GVls.GServer : GLib.Object, ContainerHashable, Server
owned get {
var l = new GContainer ();
// Scan the document to find keywords
var sc = new GVls.GScanner.with_file (file);
GScanner sc;
if ("file:///@RootServer@/" in file.get_uri ()) {
sc = new GVls.GScanner.from_string (content);
} else {
sc = new GVls.GScanner.from_file (file);
}
message ("Scanner content: %s", content);
sc.keyword.connect ((k)=>{
l.add (k);
});
......
......@@ -47,6 +47,11 @@ public interface GVls.Range : Object {
* The range's end position.
*/
public abstract Position end { get; }
public virtual string to_string () {
string str = "Range[l%d:c%d,l%d:c%d]".printf (start.line, start.character, end.line, end.character);
return str;
}
}
public interface GVls.Position : Object {
......
......@@ -35,6 +35,12 @@ public interface GVls.Server : GLib.Object, ContainerHashable
*
*/
public abstract GLib.File file { get; }
/**
* If the string to parse is not from a file, then use this
* as a content buffer, parsing hapends any time you
* set this property.
*/
public abstract string content { get; set; }
/**
*
*/
......@@ -70,7 +76,7 @@ public interface GVls.Server : GLib.Object, ContainerHashable
try {
add_namespace (ns);
} catch (GLib.Error e) {
warning ("Error adding namespace from directive: %s", e.message);
message ("Error adding namespace from directive: %s", e.message);
}
});
}
......
......@@ -17,6 +17,7 @@
*/
using GVls;
using GVlsui;
using Gtk;
public class GVlsui.SourceView : Gtk.SourceView
{
......@@ -29,6 +30,11 @@ public class GVlsui.SourceView : Gtk.SourceView
set {
_server = value;
_prov.server = _server;
get_buffer ().create_tag ("bold", "weight", 1);
get_buffer ().create_tag ("type", "weight", 1, "foreground", "#3465a4");
get_buffer ().create_tag ("keyword", "weight", 1, "foreground", "#4e9a06");
get_buffer ().create_tag ("text", "weight", 0, "foreground", "#729fcf");
get_buffer ().create_tag ("number", "weight", 1, "foreground", "#ad7fa8");
}
}
......@@ -40,12 +46,14 @@ public class GVlsui.SourceView : Gtk.SourceView
b.highlight_matching_brackets = true;
b.highlight_syntax = true;
_prov = new GVlsui.CompletionProvider ();
_prov.current_server.content = "";
try {
get_completion ().add_provider (_prov);
get_buffer ().changed.connect (()=>{
if (_server == null) return;
try {
_prov.current_server.parse_string (get_buffer ().text);
_prov.current_server.content = get_buffer ().text;
apply_syntax_highlight ();
} catch (GLib.Error e) {
warning ("Error parsing buffer: %s", e.message);
}
......@@ -54,4 +62,36 @@ public class GVlsui.SourceView : Gtk.SourceView
warning ("Error setting completion provider: %s", e.message);
}
}
public void apply_syntax_highlight () {
GVls.Container syms = _prov.current_server.document_symbols;
message ("DocumentSymbols: %u", syms.get_n_items ());
for (int i = 0; i < syms.get_n_items (); i++) {
DocumentSymbol sym = syms.get_item (i) as DocumentSymbol;
Gtk.TextIter start;
message ((sym as Symbol).location.to_string ());
if (sym.range.start.line < 0 ||
sym.range.start.character < 0 ||
sym.range.end.line < 0 ||
sym.range.end.character < 0) {
message ("Symbol skiped: %s", sym.name);
continue;
}
get_buffer ().get_iter_at_line_offset (out start, sym.range.start.line, sym.range.start.character);
Gtk.TextIter end;
get_buffer ().get_iter_at_line_offset (out end, sym.range.end.line, sym.range.end.character);
message ("Current Symbol: %s - Loc: %s", sym.name, sym.range.to_string ());
switch (sym.kind) {
case GVls.SymbolKind.KEY:
get_buffer ().apply_tag_by_name ("keyword", start, end);
break;
case GVls.SymbolKind.CLASS:
case GVls.SymbolKind.INTERFACE:
case GVls.SymbolKind.STRUCT:
case GVls.SymbolKind.ENUM:
case GVls.SymbolKind.NAMESPACE:
get_buffer ().apply_tag_by_name ("type", start, end);
break;
}
}
}
}
......@@ -42,6 +42,24 @@ test ('client-parse', tsp,
)
files_server_format = files ([
'test-server-format.vala',
])
tsf = executable('server-format', files_server_format,
vala_args : [],
dependencies : [ gvls_deps, inc_libh_dep, inc_rooth_dep],
link_with: lib
)
test ('server-format', tsf,
env: [
'BUILD_DIR='+meson.current_build_dir(),
'SRC_DIR='+join_paths(meson.source_root (), 'tests')
]
)
gtktester = dependency('gtktester-1', required: false)
if gtk_dep.found () and gtktester.found ()
subdir('ui')
......
/* -*- Mode: Vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* libvda Unit Tests
* Copyright (C) Daniel Espinosa Ortiz 2018 <esodan@gmail.com>
*
* libgda is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libgda 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using GVls;
class Tests {
static int main (string args[])
{
GLib.Intl.setlocale (GLib.LocaleCategory.ALL, "");
Test.init (ref args);
Test.add_func ("/gvls/format/document-symbols",
()=>{
var envp = GLib.Environ.get ();
string SRC_DIR = GLib.Environ.get_variable (envp, "SRC_DIR");
GLib.File file = GLib.File.new_for_path (SRC_DIR+"/parse.vala");
assert (file.query_exists ());
Server server = new GServer () as Server;
try {
server.parse (file);
message ("Symbols Found: %u", server.symbols.get_n_items ());
message ("Keywords Found: %u", server.keywords.get_n_items ());
assert (server.keywords.get_n_items () > 0);
var sd = server.document_symbols;
assert (sd.get_n_items () != 0);
message ("DocumentSymbol Found: %u", sd.get_n_items ());
for (int i = 0; i < sd.get_n_items (); i++) {
var sym = sd.get_item (i) as DocumentSymbol;
assert (sym != null);
message ("DocumentSymbol found: %s", sym.name);
}
} catch (GLib.Error e) {
message ("Error: %s", e.message);
assert_not_reached ();
}
});
return Test.run ();
}
}
......@@ -389,31 +389,6 @@ class Tests {
assert_not_reached ();
}
});
Test.add_func ("/gvls/format/document-symbols",
()=>{
var envp = GLib.Environ.get ();
string SRC_DIR = GLib.Environ.get_variable (envp, "SRC_DIR");
GLib.File file = GLib.File.new_for_path (SRC_DIR+"/parse.vala");
assert (file.query_exists ());
Server server = new GServer () as Server;
try {
server.parse (file);
message ("Symbols Found: %u", server.symbols.get_n_items ());
message ("Keywords Found: %u", server.keywords.get_n_items ());
assert (server.keywords.get_n_items () > 0);
var sd = server.document_symbols;
assert (sd.get_n_items () != 0);
message ("DocumentSymbol Found: %u", sd.get_n_items ());
for (int i = 0; i < sd.get_n_items (); i++) {
var sym = sd.get_item (i) as DocumentSymbol;
assert (sym != null);
message ("DocumentSymbol found: %s", sym.name);
}
} catch (GLib.Error e) {
message ("Error: %s", e.message);
assert_not_reached ();
}
});
return Test.run ();
}
}
......@@ -20,3 +20,23 @@ test ('sourceview', tuisw,
'SRC_DIR='+join_paths(meson.source_root (), 'tests')
]
)
files_svf = files ([
'test-sourceview-format.vala',
])
tuiswf = executable('sourceview-format', files_svf,
vala_args : [],
dependencies : [ gvlsui_deps, gtktester, inc_rooth_dep],
link_with: [
lib, libui
]
)
test ('sourceview-format', tuiswf,
env: [
'BUILD_DIR='+meson.current_build_dir(),
'SRC_DIR='+join_paths(meson.source_root (), 'tests')
]
)
/* -*- Mode: Vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* libvdaui Unit Tests
* Copyright (C) Daniel Espinosa Ortiz 2018 <esodan@gmail.com>
*
* libgda is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libgda 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using GVls;
using GVlsui;
class Tests {
static int main (string args[])
{
GLib.Intl.setlocale (GLib.LocaleCategory.ALL, "");
Test.init (ref args);
Gtk.init (ref args);
Test.add_func ("/gvlsui/sourceview/format/symbols",
()=>{
Server server = new GServer () as Server;
try {
var win = new Gtkt.WindowTester ();
var w = new GVlsui.SourceView ();
assert (w.buffer != null);
w.hexpand = true;
w.set_wrap_mode (Gtk.WrapMode.WORD);
w.set_auto_indent (true);
w.set_indent_on_tab (true);
win.waiting_for_event = true;
w.server = server;
win.widget = w;
win.add_test ("Syntax highligth", "keywords/types");
win.initialize.connect (()=>{
message ("Setting Text to Buffer");
w.buffer.text = """
public class Test {}
public class ATest {}
""";
});
win.show_all ();
Gtk.main ();
} catch (GLib.Error e) {
message ("Error: %s", e.message);
assert_not_reached ();
}
});
return Test.run ();
}
}
......@@ -41,7 +41,7 @@ class Tests {
w.set_wrap_mode (Gtk.WrapMode.WORD);
w.set_auto_indent (true);
w.set_indent_on_tab (true);
win.waiting_for_event = false;
win.waiting_for_event = true;
w.server = server;
win.widget = w;
win.add_test ("Parse pre-defined buffer", "A text on view should be parsed. Try to use a symbol");
......@@ -158,9 +158,6 @@ public class App {
""";
message ("Current Servers: %u", server.servers.get_n_items ());
for (int i = 0; i < server.servers.get_n_items (); i++) {
message ("Server: %s", (server.servers.get_item (i) as Server).file.get_uri ());
}
assert (server.servers.get_n_items () == 3);
assert (server.get_symbol ("t") != null);
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment