Gedit」タグアーカイブ

Gedit 3.14 Plugin

そろそろ新しい Fedora が出るので準備をしなければ。
ベータが出ているようなので試す、面倒だから久々に仮想マシン。

boxes

Boxes(qemu-kvm) はやはり超簡単というか全自動です。
Fedora on Fedora なら 3D デスクトップもストレスが無いのが嬉しい。
細かい指定はできないけどテスト目的には十分すぎる。

ただ Live 中はフル HD なのを認識したのにインストール後は SXGA に。
相変わらずよく解らない認識をする、フル HD 固定だとそれも困るわけですが。
筆者はウインドウモードで使うので 1440×900 に固定。

インストール直後に生 XML から iso を排除する必要はなくなったみたい。
Boxes の設定画面[デバイス]の CD/DVD の所で取り外しできる。

cd_dvd

Alt+Space がウインドウメニューに割り当てされているや。
US キーボードなのでコレで入力切り替えできないと不便なんだよ。
まあ設定で簡単に変えられるのでちゃっちゃと変更。

header_bar

いやぁ、見事に GtkHeaderBar 化されて…
っておい Eye of GNOME さん、あんたが一番メニューバー邪魔でしょ。
これ以上の変更点レビューは正式版の時に。

とにかく Gedit はメニューバーが無いので以前の自作プラグイン達は使えない。

Apps/Gedit/PythonPluginHowTo – GNOME Wiki!
残念ながら 2014.11.16 現在チュートリアルは以前のままだ。

Gedit 3.12 をスルーしたおかげで日本語の先人を見つけた。

うぇーん、GNOME 3.12 にしたら、自家製Linespacing が動かないよー | (まだ無題 ; そのうち変更するかも)

メニュー項目は GMenu 化、GtkApplication 側に登録。
ハンドラは GAction として GtkWindow 側に登録するみたい。
GtkUIManager 関連を消すのを忘れているみたいですけど。

なんか上手くいかないので QuickOpen のソースを参考に少し作り替え。
*.plugin ファイルは以前と同じでいいようです。

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

from gi.repository import GObject, Gedit, Gtk, Gio

class TestTestAppActivatable(GObject.Object, Gedit.AppActivatable):
    """
        Set GMenu and Accelerator
    """
    app = GObject.property(type=Gedit.App)

    def __init__(self):
        GObject.Object.__init__(self)

    def do_activate(self):
        # Set Accelerator
        # (key, action name[win.xxxxx], parameter or None)
        self.app.add_accelerator("<Control>B", "win.action_name", None)
        # Append Menu
        self.menu_ext = self.extend_menu("tools-section")
        item = Gio.MenuItem.new("imouto",  "win.action_name")
        self.menu_ext.append_menu_item(item)

    def do_deactivate(self):
        # Remove Accelerator
        self.app.remove_accelerator("win.action_name", None)

class TestTest(GObject.Object, Gedit.WindowActivatable):
    """
        Set GAction
    """
    __gtype_name__ = "TestTest"
    window = GObject.property(type=Gedit.Window)
    def __init__(self):
        GObject.Object.__init__(self)

    def do_activate(self):
        # Set Action
        # (action name, parameter or None)
        action = Gio.SimpleAction.new("action_name", None)
        action.connect('activate', self.on_activate)
        self.window.add_action(action)

    def do_deactivate(self):
        # Remove Action
        self.window.remove_action("action_name")

    def do_update_state(self):
        pass

    def on_activate(self, action, data=None):
        self.messagebox("Yamete Oni-chan")

    def messagebox(self, text):
        dlg = Gtk.MessageDialog(
                self.window,
                Gtk.DialogFlags.MODAL,
                Gtk.MessageType.WARNING,
                Gtk.ButtonsType.OK,
                text)
        r = dlg.run()
        dlg.destroy()

gedit314_plugin

こんな感じで。

とりあえずアクション名を決める。
GtkApplication 側で使う場合は win.xxxxx と接頭子を付ける。
こうしないとメニューがアクティブにならなかった。

次はアクション名にアクセラレータキーに紐付ける
そしてメニューに表示する文字列を決め GMenu を作成。
それをメニューのどこかに突っ込む。
file-section, tools-section, view-section-2 等々。

本体側は先程のアクション名で GAction を作る。
シグナルハンドラをセットし本体に登録、コッチは簡単だね。
後は今迄どおりでいいみたい。

Eye of GNOME プラグインは変更しなくてもいいかな?と思ったけどダメだった。
と思ったら *.plugin の Loader=python3 書き換えだけでイケた。

eog314plugin

Python3 なので unicode 等の処理をお忘れなく。

xkill

最近 xkill というコマンドを知った。
今まで debug 中の自作 GUI アプリを強制終了する場合は端末を起動し

ps ax | grep hoge
12345 ****
kill 12345

kill

みたいに古臭い手段でやっていた。
xkill ならコマンド実行後にマウスでクリックするだけ、簡単すぎ。

端末から debug 起動なら端末を終了すればいいけど筆者は下記なので。
Gedit で Python スクリプトを debug – L’Isola di Niente

とはいえ今時の Linux では debug の時くらいしか利用しないコマンド。
いざ必要になった時にコマンドを忘れてしまう、筆者だけかそんな奴。
なので忘れてもいいように Gedit から起動するように外部ツールに登録。

xkill

これでスクリプトの debug が少し楽になるといいな。
Python はまだいい、Gjs ってエラーも吐かずにフリーズが多すぎる…

Gedit(GtkSourceView) Alt+Up/Down

Gedit で何気無く Alt+Up を叩いたら行が上下で入れ替わった。
複数行を選択して同様に叩いても動作するようだ。

GtkSourceView 3 Reference Manual: GtkSourceView

GtkSourceView の標準機能だった、GtkTextView ではできません。
本当にウイジェットだけで動作するかチト試してみる。

#!/usr/bin/env python3

from gi.repository import Gtk, GtkSource

TEXT = """

TextBlock

Press `Alt + Up`
Move the Selection Text
"""

class AltUpTest(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        # Create GtkSourceView
        view = GtkSource.View()
        view.set_show_line_numbers(True)
        # buffer
        buf = view.get_buffer()
        buf.set_text(TEXT)
        # Select
        it = buf.get_iter_at_offset(13)
        itend = buf.get_end_iter()
        buf.select_range(it, itend)
        # self
        self.add(view)
        self.connect("delete-event", Gtk.main_quit)
        self.set_title("Test")
        self.show_all()

AltUpTest()
Gtk.main()

alt_up

マジだった。
つまり GtkSourceView 採用のアプリなら全部可能だということ。
DnD 編集が標準だったり GTK+ 便利すぎだろ。

Windows 用 Gedit 2.30 でも同様。
ただし Alt+Left/Right での英単語移動は GTK3 からなので使えない。

Gedit を五年以上使い続けているのに今頃気が付いた私って…

Gedit for Windows part3

Gedit Windows 版から IronPython を起動する。
Python コードを開いて F5 キーを叩くと実行結果をボトムパネルに表示。
Gedit で Python スクリプトを debug – L’Isola di Niente
つまりコレを再現したい。

Gedit の Windows 版で External Tools が使えないのでソースコードを見る。
ちなみに External Tools も Python 製である。
8.11 fcntl — fcntl() および ioctl() システムコール
を使っていた、なるほどこれでは Windows では使えないわけだ。

前回は少し勘違いをしていたようで環境変数は External Tools が登録するようだ。
何にせよ Linux と Windows でまったく同じコードというのは不可能だよね。

とりあえず Python なんだから subprocess でなんとかならないか。
window オブジェクトからロケーションは得られるのだから強引にでも。

と思ってこんなプラグインを作ってみた。

ipyexec.gedit-plugin

[Gedit Plugin]
Loader=python
Module=ipyexec
IAge=2
Name=Iron Python Execute
Description=Iron Python Execute
Authors=sasakima-nao <sasakimanao@gmail.com>
Copyright=Copyright © 2013 sasakima-nao <sasakimanao@gmail.com>
Website=http://palepoli.skr.jp/

ipyexec.py

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

import gedit
import gtk
import os
import subprocess

IPYPATH = "C:\Program Files (x86)\IronPython 2.7\ipyw64.exe"

ui_str = """<ui>
    <menubar name="MenuBar">
        <menu name="ToolsMenu" action="Tools">
            <menuitem name="ipyexec" action="ipyexec"/>
        </menu>
    </menubar>
</ui>
"""

class IpyExecPlugin(gedit.Plugin):
    def __init__(self):
        gedit.Plugin.__init__(self)

    def activate(self, window):
        self._window = window
        manager = self._window.get_ui_manager()
        self._action_group = gtk.ActionGroup("IpyExecActions")
        # GtkActionEntry
        # name, stock_id, label, accelerator, tooltip, callback
        actions = [("ipyexec", None, "ipyexec", "F5", "ipyexec", self.on_ipyexec_activate)]
        self._action_group.add_actions(actions)
        manager.insert_action_group(self._action_group, -1)
        self._ui_id = manager.add_ui_from_string(ui_str)
        # Panel
        self.textview = gtk.TextView()
        self.textview.show()
        self.outputpanel = gtk.ScrolledWindow()
        self.outputpanel.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.outputpanel.set_shadow_type(gtk.SHADOW_IN)
        self.outputpanel.show()
        self.outputpanel.add(self.textview)
        bottom = self._window.get_bottom_panel()
        bottom.add_item(self.outputpanel, "Output", "Output")

    def deactivate(self, window):
        manager = self._window.get_ui_manager()
        manager.remove_ui(self._ui_id)
        manager.remove_action_group(self._action_group)
        manager.ensure_update()
        # Panel
        bottom = self._window.get_bottom_panel()
        bottom.remove_item(self.outputpanel)

    def update_ui(self, window):
        pass

    def on_ipyexec_activate(self, action):
        # Show Buttom Panel
        bottom = self._window.get_bottom_panel()
        bottom.show()
        # Buffer
        buf = self.textview.get_buffer()
        # Get full path
        view = self._window.get_active_view()
        doc = view.get_buffer()
        location = doc.get_location()
        path = location.get_path()
        # Popen
        popen = subprocess.Popen(
                [IPYPATH, path],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE )
        output = popen.communicate()
        if output[1]:
            buf.set_text("Do IronPython\n\n%s\nDone." % output[1])
        else:
            if output[0]:
                buf.set_text("Do IronPython\n\n%s\nDone." % output[0])
            else:
                buf.set_text("Do IronPython\n\nNo Output\n\nDone.")

ipyexec

なんとか動く、かなり手抜きくさいのはご了承。
External Tools と違って終了するまで値が戻ってこない仕様ですんで。

小物ならコレで問題ないけど Application クラスを使うとなると…
即座に stderr を検知したいけど、手段が解らないです。

拡張子判別をしてアプリを振り分ける手もあるけど私的にはコレでいい。
別の言語で起動させたい人はお好みに書き換えてください。

これ以上改造するにしても、GTK2, gconf, Python2, PyGtk…
本体及びプラグインの構成部品がことごとく既に開発終了しているという現実がね。
Gedit3 の Windows パッケージが出るならもう少し本気になるかも。

ということで。
Linux でも Windows でも動くことを考慮しなければプラグインは作れます。
ただ Windows で PyGtk を勉強しても他で何も役に立たない、しかも開発終了品。
なので他人に勧め辛いのが難点、Python の勉強にはなるけど。
もっとイイのを誰かに作ってほしいな(ぉい!

# 2013.11.09 追記
日本語出力ができなかった、日本語 Windows の stdout は cp932 なので変換。
それと output を別スレッドにして動作を判り易く改良してみた。
終了まで出力しないのは変わらないけど。

#-*- coding:utf8 -*-

import gedit
import gtk
import os
import subprocess
import glib

IPYPATH = "C:\Program Files (x86)\IronPython 2.7\ipyw64.exe"

ui_str = """<ui>
    <menubar name="MenuBar">
        <menu name="ToolsMenu" action="Tools">
            <menuitem name="ipyexec" action="ipyexec"/>
        </menu>
    </menubar>
</ui>
"""

class IpyExecPlugin(gedit.Plugin):
    def __init__(self):
        gedit.Plugin.__init__(self)

    def activate(self, window):
        self._window = window
        manager = self._window.get_ui_manager()
        self._action_group = gtk.ActionGroup("IpyExecActions")
        # GtkActionEntry
        # name, stock_id, label, accelerator, tooltip, callback
        actions = [("ipyexec", None, "ipyexec", "F5", "ipyexec", self.on_ipyexec_activate)]
        self._action_group.add_actions(actions)
        manager.insert_action_group(self._action_group, -1)
        self._ui_id = manager.add_ui_from_string(ui_str)
        # Panel
        self.textview = gtk.TextView()
        self.textview.show()
        self.outputpanel = gtk.ScrolledWindow()
        self.outputpanel.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.outputpanel.set_shadow_type(gtk.SHADOW_IN)
        self.outputpanel.show()
        self.outputpanel.add(self.textview)
        bottom = self._window.get_bottom_panel()
        bottom.add_item(self.outputpanel, "Output", "Output")

    def deactivate(self, window):
        manager = self._window.get_ui_manager()
        manager.remove_ui(self._ui_id)
        manager.remove_action_group(self._action_group)
        manager.ensure_update()
        # Panel
        bottom = self._window.get_bottom_panel()
        bottom.remove_item(self.outputpanel)

    def update_ui(self, window):
        pass

    def on_ipyexec_activate(self, action):
        # Show Buttom Panel
        bottom = self._window.get_bottom_panel()
        bottom.show()
        # Write
        buf = self.textview.get_buffer()
        buf.set_text("Do IronPython\n\n")
        glib.idle_add(self.on_idle)

    def on_idle(self):
        # Buffer
        buf = self.textview.get_buffer()
        it = buf.get_end_iter()
        # Get full path
        view = self._window.get_active_view()
        doc = view.get_buffer()
        location = doc.get_location()
        path = location.get_path()
        # Popen
        popen = subprocess.Popen(
                [IPYPATH, path],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE )
        output = popen.communicate()
        if output[1]:
            buf.insert(it, "%s\nError." % output[1])
        elif output[0]:
            #buf.insert(it, "%s\nDone." % output[0])
            s = unicode(output[0], encoding='cp932').encode("utf8")
            buf.insert(it, "%s\nDone." % s)
        else:
            buf.insert(it, "Done.")
        return False

####################

Gedit には grep 機能が無い?
元が Linux のエディタだよ、皆 grep コマンドを使っているからあるわけない。

だから WindowsPowerShell で Select-String コマンドを使いなさい。
つか grep というエイリアスを作ることもできる。
Windows PowerShell の機能

mkdir WindowsPowerShell
cd WindowsPowerShell
echo Set-Alias grep Select-String > Microsoft.PowerShell_profile.ps1

ドキュメントディレクトリでこんなバッチを動かせば一発よん。

grep

パイプによる stdout も受け付けるし grep コマンドとほぼ同様。
まさか Gedit で grep プラグインを探している偽 Linux 使いはいませんよね。

Gedit for Windows part2

さてプラグインだが。
プラグインはほとんど Python で作られているのはご存知のとおり。
このマシンでは IronPython しか入れていないのだが。
同梱の組込 Python2.6 でプラグインを動かすということみたい。

Python で作られているコードスニペットプラグインを有効にする。
拡張子を py にしたファイルを開き py と打ち込んで Tab キーを叩く。

gedit_py

キチンと動作する、Python2 を別途で用意する必要は無いようだ。
つか EmEditor の外部ツールと違ってバカ早い、

って、だから Windows ではテキストファイルの一行目に特別な意味なんて無い。
@Linux では実行パーミッション時に一行目プログラムで動かす、拡張子は無意味
本当に Linux のものを Windows で動かせるようにしただけなんだとよく判る例。

ちなみにスニペットを変更すると

%USERPROFILE%\.gnome2\gedit\snippets

に変更データが入る、なるほど Linux と同じなんだ。

どうでもいいけど Explorer ではドットで始まる名前のファイルが作れない。
MKDIR コマンドなら作れる、大きなお世話だ。

ならばプラグインも
%USERPROFILE%\.gnome2\gedit\pligins
でイケそうなのに認識してくれない。

Gedit – Tutorials – SCOL Language

うーん、Program Files (x86) 以下に入れるしか手段が無いみたいだ。
%PROGRAMFILES(X86)%\gedit\lib\gedit-2\plugins

programfiles

しかたがないので管理者権限で Explorer を起動。
以下の自作プラグインをひたすらコピー、Gedit2 だから v1 のほうね。
Gedit 及び Eye of Gnome プラグイン

おぉ動く、LFonBR は CRLF だと CR 部が改行されちゃうけどね。
とりあえず Linux 依存(パス区切り等)の部分が無いなら動くのね。

しかし External tools が無いのは痛い。

Apps/Gedit/Plugins – GNOME Wiki!

標準にあるはずなんだが、External tools の More を見る。
GLib からでは環境変数が登録できないってことかな。
面倒くさいけどチェックするプラグインでもテキトーに作るか。

test.gedit-plugin

[Gedit Plugin]
Loader=python
Module=test
IAge=2
Name=Test
Name[ja]=テスト
Description=test
Description[ja]=テスト
Authors=sasakima-nao 
Copyright=Copyright © 2009 sasakima-nao 
Website=http://palepoli.skr.jp/

test.py

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

import gedit
import gtk
import os

ui_str = """<ui>
	<menubar name="MenuBar">
		<menu name="EditMenu" action="Edit">
			<placeholder name="EditOps_3">
				<menuitem name="test" action="test"/>
			</placeholder>
		</menu>
	</menubar>
</ui>
"""

class HtmlEscapePlugin(gedit.Plugin):
	def __init__(self):
		gedit.Plugin.__init__(self)

	def activate(self, window):
		self._window = window
		manager = self._window.get_ui_manager()
		self._action_group = gtk.ActionGroup("TestActions")
		# GtkActionEntry
		# name, stock_id, label, accelerator, tooltip, callback
		actions = [("test", None, "test", None, "test", self.on_test_activate)]
		self._action_group.add_actions(actions)
		manager.insert_action_group(self._action_group, -1)
		self._ui_id = manager.add_ui_from_string(ui_str)
		
	def deactivate(self, window):
		manager = self._window.get_ui_manager()
		manager.remove_ui(self._ui_id)
		manager.remove_action_group(self._action_group)
		manager.ensure_update()
		

	def update_ui(self, window):
		pass
	
	def on_test_activate(self, action):
		# Check
		s = os.environ["USERNAME"]
		self.messagebox(s)
		try:
			# echo %GEDIT_CURRENT_DOCUMENT_PATH%
			s = os.environ["GEDIT_CURRENT_DOCUMENT_PATH"]
			self.messagebox(s)
		except:
			self.messagebox("No %GEDIT_CURRENT_DOCUMENT_PATH%")
		
	def messagebox(self, text):
		dlg = gtk.MessageDialog(self._window,  
								gtk.DIALOG_MODAL,  
								gtk.MESSAGE_WARNING, 
								gtk.BUTTONS_OK,  
								text)  
		r = dlg.run()  
		dlg.destroy()

error

あぁやっぱり。
これじゃ自力でも外部ツールは作れないよ。
IronPython をエディタから起動したかったんだが困った。