Скрещивание Julia и Scintilla
Свет в тёмном царстве
Julia — новый, красивый и эффективный опенсорсный язык программирования с JIT-компиляцией, ориентированный на вычислительные задачи. Scintilla — кроссплатформенный контрол, представляющий из себя развитый редактор кода, используемый, например, в Notepad++ и Geany. Скрещивание этих двух зверей есть эксперимент по привлечению в математический мир Джулии элементов графического интерфейса.
Эльф
Первое, что нам понадобится, это сама Scintilla. Однако так как прилинковывать объектные файлы к Джулии нельзя, то нам необходима динамическая библиотека. Я сотворил эльф для себя (Debian 7) на основе примера bait, исходников Scintilla v3.3.7 и немного подправленного мейкфайла со следующей командой:
so: so.o $(LEXEROBJS) ../scintilla/bin/scintilla.a
gcc -shared -DGTK $^ -o libscintilla.so \
-lstdc++ `pkg-config --libs $(GTKVERSION) \
gthread-2.0` -lm -lgmodule-2.0
Это создаёт динамическую (shared
) библиотеку со связью к gtk2.
Julia имеет неплохие возможности по взаимодействию с С-библиотеками, так что далее — дело техники.
Через Силу
API Scintilla обширно использует всяческие флаги и константы, так что нам позарез нужен файл, содержащий все или хотя бы самые необходимые из констант:
INVALID_POSITION = -1
SCI_START = 2000
SCI_OPTIONAL_START = 3000
SCI_LEXER_START = 4000
SCI_ADDTEXT = 2001
SCI_ADDDTEXT = 2002
SCI_INSERTTEXT = 2003
...
Правильно было бы обозначить данные константы как константы, а не как переменные, но Julia (0.2) очень строго относится к константам, требуя их обязательный поимённый экспорт из модуля для внешнего использования, так что мы просто на этот раз не будем менять значения констант.
Враппинг C API делается следующим образом:
function scintilla_send_message(sci, m, w, l::Int32)
ccall( (:scintilla_send_message, libscintilla),
Int32, (Int32, Int32, Int32, Int32), sci, m, w, l)
end
В принципе, на этом к счастью Scintilla API и заканчивается.
Использование
Теперь создаём GTK-окно, контрол Scintilla, вставляем одно в другое, щепотка настройки — и активируем:
w = 600
h = 400
mainwin = Window("bit_ch", 800, 600)
editor = scintilla_new()
ccall((:gtk_container_add,libgtk), Void, (Int32,Int32,),
mainwin.handle, editor)
scintilla_send_message(editor,
SCI_STYLESETFONT, STYLE_DEFAULT, "Monospace")
scintilla_send_message(editor,
SCI_SETMARGINWIDTHN, 0, 64)
scintilla_send_message(editor,
SCI_SETTABWIDTH, 4, 0)
ccall( (:gtk_widget_show_all, libgtk), Void, (Int32,),
mainwin.handle )
show(STDOUT, mainwin)
Если нужно повесить обработчик сигнала, то это можно сделать примерно так:
function cb1(::Int32, ::Int32, widget::Int32)
println("delete_event")
return 0::Int32
end
ccall( (:g_signal_connect_data,libgobject),
Int32,
(
Int32,
Ptr{Uint8},
Ptr{Void},
Int32,
Int32,
Int32
),
mainwin.handle,
bytestring("delete_event"),
cfunction(cb1, Int32, (Int32,Int32,Int32)),
0,
0,
0
)
Здесь мы воспользовались прямым C-вызовом к GTK, хотя джулевский модуль Gtk.jl предлагает свои более высокоуровневые методы, но я лично не смог заставить их корректно работать.
Вот так вот
Как видим, из Julia можно более-менее сносно использовать любые имеющиеся C-модули. Но, конечно, привнесение C-интерфейсов в среду Julia нарушает стилистику последнего, поэтому, по-хорошему, оно требует написания отдельного обволакивающего модуля.
Ссылки:
- язык Julia
- пример простейшего использоваания Scintilla bait
- исходники контрола Scintilla v3.3.7
- мейкфайл для компиляции динамического эльфа
- скомпилированная libscintilla.so
- модуль Julia с константами Scintilla
- модуль Julia, создающий окно и контрол Scintilla в нём
Всем удачного использования достижений open source!
shitpoet@gmail.com