Скрещивание 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 нарушает стилистику последнего, поэтому, по-хорошему, оно требует написания отдельного обволакивающего модуля.

Ссылки:

Всем удачного использования достижений open source!

 

shitpoet@gmail.com

 



 

free hit counters