PyGTKで作ったエディタ、製作状況など。


暇を見てはチクチクと作っていたエディタ、こんな感じになってきました。
リファクタリングしていたら、「こっちのほうがいいかな。。」、「いや、まてよ。。」とか
いろいろアイディアが。。。いかんいかん。リファクタリングと機能追加のフェーズは分けないと。


ということで、リファクタリングを済ませたあとで、いろいろと手直ししました。
(ほとんど作り直した。。という話もあります)



主な機能は、

(1) バッファ管理機能を追加。
(2) ウインドウ分割機能を追加。
(3) キーバインド定義機能。(以前のものよりも設定しやすくなったと思います)
(4) 関数管理機能の追加。
(5) シンタックスカラーリングに対応。

その他、細かい設定がすこしだけできます。


(1) バッファ管理機能
  この機能は、外見的にはほとんどわかりません。
  が、結構重要(だと思っています)。
  GTKのサンプルなどでは、1つのSourceViewに対して1つのSourceBufferを割り当てるものが多いですが、
  今回はSourceViewとSourceBufferをあえて切り離して管理しています。


  そうすることで、同じファイルを開いた場合のSourceBufferの管理や、あるSourceBufferのテキストを別々のSourceViewで
  表示させる場合に柔軟に対応できそうだからです。


(2) ウインドウ分割機能
  これは上記の(1)で書いたことに関連しています。SourceBufferの管理をSourceViewとは切り離してあるので、
  テキストの縦・横分割表示ができるようになりました。


(3) キーバインドの定義
  この機能は前々からできていたのですが、もっと簡単に設定できるように
  しました。現状ではPythonスクリプトで設定する方法のみに対応していますが、
  ゆくゆくは、GUI/Pythonスクリプトの両方で設定できるような仕組みをつくろうと思っています。


  キーバインド定義用のpyファイルは以下のようになっています。

# -*- coding: utf-8 -*-

from rc.keyconf import register_keybind

#
# Emacs風キーバインド登録
#
# register_keybind(category, key, func-name, description)
#    category   : キー操作のカテゴリ。
#                 ('editor'はテキストエディタで使用されるキーバインドを意味する)
#    key        : キー操作文字列をタプルで指定。
#                emacsのC-x, C-cのような多段キーも指定可能。--> ('<control>x', '<control>c')
#    func-name  : 実行すべき関数の名前
#    description: 説明文(オプション)

register_keybind('editor', ('<control>f',), 'move_forward', description=None)
register_keybind('editor', ('<control>b',), 'move_backward', description=None)
register_keybind('editor', ('<control>p',), 'move_prev_line', description=None)
register_keybind('editor', ('<control>n',), 'move_next_line', description=None)
register_keybind('editor', ('<control>a',), 'move_line_head', description=None)
register_keybind('editor', ('<control>e',), 'move_line_tail', description=None)
register_keybind('editor', ('<control>h',), 'delete_prev_char', description=None)
register_keybind('editor', ('<control>d',), 'delete_next_char', description=None)
register_keybind('editor', ('<control><mod1>h',), 'delete_prev_word', description=None)
register_keybind('editor', ('<control><mod1>d',), 'delete_next_word', description=None)
register_keybind('editor', ('<control>k',), 'delete_to_line_tail', description=None)
register_keybind('editor', ('<control><space>',), 'set_mark', description=None)


(4) 関数管理機能
  この機能、エディタ起動時に所定のPythonスクリプト中で登録された関数を
  好きなタイミングで実行できるようにするための機能です。
  「キーバインドの定義」も実はこの機能を使用しています。
  つまり、キーが押されるたびに、登録されている関数を呼び出しているわけです。
  ゆくゆくは「マクロの実行」的な使い方にも使えるかもしれません。

# -*- coding: utf-8 -*-

import sys
import pygtk
if sys.platform != 'win32':
    pygtk.require('2.0')
import gtk

from rc.functionconf import register_function


#
# 関数定義部
#
def __move_forward(editor):
    marked = editor.get_marked()
    editor.emit('move-cursor', gtk.MOVEMENT_VISUAL_POSITIONS, 1, marked)

def __move_backward(editor):
    marked = editor.get_marked()
    editor.emit('move-cursor', gtk.MOVEMENT_VISUAL_POSITIONS, -1, marked)

def __move_prev_line(editor):
    marked = editor.get_marked()
    editor.emit('move-cursor', gtk.MOVEMENT_DISPLAY_LINES, -1, marked)

def __move_next_line(editor):
    marked = editor.get_marked()
    editor.emit('move-cursor', gtk.MOVEMENT_DISPLAY_LINES, 1, marked)

def __move_line_head(editor):
    marked = editor.get_marked()
    editor.emit('move-cursor', gtk.MOVEMENT_PARAGRAPH_ENDS, -1, marked)

def __move_line_tail(editor):
    marked = editor.get_marked()
    editor.emit('move-cursor', gtk.MOVEMENT_PARAGRAPH_ENDS, 1, marked)

def __delete_prev_char(editor):
    editor.emit('delete-from-cursor', gtk.DELETE_CHARS, -1)
    editor.emit('set-mark', False)

def __delete_next_char(editor):
    editor.emit('delete-from-cursor', gtk.DELETE_CHARS, 1)
    editor.emit('set-mark', False)

def __delete_prev_word(editor):
    editor.emit('delete-from-cursor', gtk.DELETE_WORDS, -1)
    editor.emit('set-mark', False)

def __delete_next_word(editor):
    editor.emit('delete-from-cursor', gtk.DELETE_WORDS, 1)
    editor.emit('set-mark', False)

def __delete_to_line_tail(editor):
    editor.emit('delete-from-cursor', gtk.DELETE_PARAGRAPH_ENDS, 1)
    editor.emit('set-mark', False)

def __set_mark(editor):
    editor.emit('set-mark', True)

    
#
# 関数登録部 
#
# register_function(category, func-name, func, description)
#    category   : カテゴリ
#                 ('editor'はテキストエディタで使用されるキーバインドを意味する)
#    func-name  : 関数名(文字列)
#    func       : 関数
#    description: 説明文(オプション)
#
register_function('editor', 'move_forward', __move_forward, None)
register_function('editor', 'move_backward', __move_backward, None)
register_function('editor', 'move_next_line', __move_next_line, None)
register_function('editor', 'move_prev_line', __move_prev_line, None)
register_function('editor', 'move_line_head', __move_line_head, None)
register_function('editor', 'move_line_tail', __move_line_tail, None)
register_function('editor', 'delete_prev_char', __delete_prev_char, None)
register_function('editor', 'delete_next_char', __delete_next_char, None)
register_function('editor', 'delete_prev_word', __delete_prev_word, None)
register_function('editor', 'delete_next_word', __delete_next_word, None)
register_function('editor', 'delete_to_line_tail', __delete_to_line_tail, None)
register_function('editor', 'set_mark', __set_mark, None)


(5) シンタックスハイライト機能など
  この機能も以前からありました。
  基本的にはPyGTKのSourceViewが持っているシンタックスハイライト機能を使っているだけです。
  MIMEタイプに応じてキーワードのハイライトを行います。
  現状ではキーワード種類ごとの色のカスタマイズ機能が完成していません。。


(6) その他
  その他にも、PyGTKのSourceViewがもっているプロパティ(タブ幅とかフォントとか)を
  カスタマイズできます。設定項目は適宜増やしていく予定です。


まずは、予定している基本的な機能を作ってから、細かい部分を作り込んでいこうと
思っています。


次なる予定は、プラグイン機能の実装です。
計画では、エディタ本体自体は基本的な機能のみを提供し、
ほとんどの機能をプラグイン化しようと思っています。


いやはや、なかなか進みませんな。。。(笑