Develop and Download Open Source Software

Browse CVS Repository

Diff of /shiki/shiki/shiki.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph | View Patch Patch

revision 1.1.1.1 by aloha, Thu Nov 2 12:07:44 2006 UTC revision 1.67 by aloha, Sun Feb 18 09:59:14 2007 UTC
# Line 2  Line 2 
2   *   *
3   * shiki.c   * shiki.c
4   *   *
5     * This file is main file of Shiki.
6     *
7   * Copyright(C)2006 WAKATSUKI toshihiro   * Copyright(C)2006 WAKATSUKI toshihiro
8   *   *
9   * Permission is hereby granted, free of charge, to any person obtaining a   * Permission is hereby granted, free of charge, to any person obtaining a
# Line 25  Line 27 
27   * $Id$   * $Id$
28   */   */
29    
30  #include<gauche.h>  #include"shiki.h"
 #include<gtk/gtk.h>  
 #include<gdk/gdkkeysyms.h>  
31    
32  #define INDENT_WIDTH 2  /* エディタ全体に関する情報と,現在表示されているタブ情報へのキャッシュを管理する構造体 */
33    ShikiEditorType Shiki_editor;
34    
35  static GtkWidget *editor_window;  static gchar *R5RS_keywords[]  = {"and", "begin", "case", "cond-expand", "cond", "define-accessor", "define-class", "defined?", "define-generic", "define", "define-macro", "define-method", "define-module", "define-private", "define-public", "define-reader-ctor", "define-syntax", "define-syntax-macro", "defmacro", "defmacro*-public", "delay", "do", "else", "fluid-let", "if", "lambda", "let", "let*", "letrec", "letrec-syntax", "let-syntax", "or", "quasiquote", "quote", "set!", "syntax-rules", "unquote", NULL};
36    
37  /* テキストバッファから全ての文字列を取り出す */  static gchar *R5RS_functions[] = {"*", "+", "-", "/", "<", ">", "<=", ">=", "?", "`", "=", "abs", "acos", "angle", "append", "apply", "asin", "assoc", "assq", "assv", "atan", "boolean?", "caaar", "caadr", "caar", "cadar", "caddr", "cadr", "call/cc", "call-with-current-continuation", "call-with-input-file", "call-with-output-file", "call-with-values", "car", "catch", "cdaar", "cdadr", "cdar", "cddar", "cdddr", "cddr", "cdr", "ceiling", "char-alphabetic?", "char-ci>=?", "char-ci>?", "char-ci=?", "char-ci<=?", "char-ci<?", "char-downcase", "char->integer", "char>=?", "char>?", "char=?", "char?", "char-lower-case?", "char<=?", "char<?", "char-numeric?", "char-ready?", "char-upcase", "char-upper-case?", "char-whitespace?", "close-input-port", "close-output-port", "complex?", "cons", "cos", "current-input-port", "current-output-port", "delete-file", "display", "dynamic-wind", "eof-object?", "eq?", "equal?", "eqv?", "eval", "even?", "exact->inexact", "exact?", "exit", "exp", "expt", "file-exists?", "file-or-directory-modify-seconds", "floor", "force", "for-each", "gcd", "gensym", "getenv", "get-output-string", "imag-part", "inexact?", "input-port?", "integer->char", "integer?", "lcm", "length", "list->string", "list->vector", "list", "list?", "list-ref", "list-tail", "load", "log", "magnitude", "make-polar", "make-rectangular", "make-string", "make-vector", "map", "max", "member", "memq", "memv", "min", "modulo", "negative?", "newline", "nil", "not", "null?", "number->string", "number?", "odd?", "open-input-file", "open-input-string", "open-output-file", "open-output-string", "output-port?", "pair?", "peek-char", "port?", "positive?", "procedure?", "quotient", "rational?", "read-char", "read", "read-line", "real?", "real-part", "remainder", "reverse", "reverse!", "round", "set-car!", "set-cdr!", "sin", "sqrt", "string-append", "string-ci>=?", "string-ci>?", "string-ci=?", "string-ci<=?", "string-ci<?", "string-copy", "string-fill!", "string>=?", "string>?",  "string->list", "string->number", "string->symbol", "string", "string=?", "string?", "string-length", "string<=?", "string<?", "string-ref", "string-set!", "substring", "symbol->string", "symbol?", "system", "tan", "truncate", "values", "vector-fill!", "vector->list", "vector", "vector?", "vector-length", "vector-ref", "vector-set!", "with-input-from-file", "with-output-to-file", "write-char", "write", "zero", NULL};
 static gchar* get_all_buffer_contents(GtkTextBuffer *buffer) {  
   GtkTextIter start, end;  
   gtk_text_buffer_get_start_iter(buffer, &start);  
   gtk_text_buffer_get_end_iter(buffer, &end);  
   return gtk_text_buffer_get_text(buffer, &start, &end, FALSE);  
 }  
38    
39  /* buffer の内容をファイル filename に保存 */  static GHashTable *keywords_hash = NULL;
40  static gboolean save_text_buffer(const gchar *filename, GtkTextBuffer *buffer) {  
41    gchar *contents, *text;  typedef enum {
42    gsize br, bw;    R5RS_KEYWORD_COLOR = 1,
43    GError *err = NULL;    R5RS_FUNCTION_COLOR,
44      GAUCHE_KEYWORD_COLOR,
45      GAUCHE_FUNCTION_COLOR
46    } HIGHILIGHT_COLOR;
47    
48    GdkColor COLOR_BLACK;
49    GdkColor COLOR_GREEN;
50    
51    /* プロトタイプ */
52    
53    /* foo_bar_handler() は,イベントハンドラのためのラッパー */
54    static void kill_buffer_handler();
55    static void append_default_tabpage_handler();
56    
57    /* ファイル関係 */
58    static void save_file();
59    static void save_file_as();
60    
61    /* テキストバッファ関係 */
62    static gchar* get_all_buffer_contents(GtkTextBuffer *buffer);
63    static gboolean save_text_buffer(const gchar *filename, GtkTextBuffer *buffer);
64    static void clear_current_buffer_handler();
65    
66    /* Gauche と S 式操作やインデント・キーワードハイライティング関連 */
67    static gchar *load_cstring_by_gauche(gchar *s);
68    static void load_buffer_by_gauche();
69    static void load_region_by_gauche();
70    static void load_scheme_file_by_gauche();
71    static gint get_parent_nest_level_at_cursor(GtkTextBuffer *buffer);
72    static gboolean is_not_scheme_delimita_p(gunichar ch, gpointer user_data);
73    static gboolean is_double_quote(gunichar ch, gpointer user_data);
74    static gboolean is_scheme_delimita_p(gunichar ch, gpointer user_data);
75    static void scheme_keyword_highlighting_current_buffer();
76    
77    /* 設定 */
78    static void select_font();
79    static void font_selection_ok(GtkWidget *button, GtkWidget *font_dialog);
80    static void switch_tabpage_handler(GtkNotebook *notebook, GtkNotebookPage *page, guint pagenum) ;
81    static void tabsborder_on_off(GtkButton *button, GtkNotebook *notebook);
82    static void rotate_tab_position(GtkButton *button, GtkNotebook *notebook);
83    
84    /* キーバインド全般 */
85    static gboolean signal_key_press_handler(GtkWidget *notebook, GdkEventKey *event, gpointer contextid);
86    static gboolean signal_key_release_handler(GtkWidget *notebook, GdkEventKey *event, gpointer contextid);
87    
88    /* ヘルプや情報 */
89    static void open_online_help();
90    static void about_this_application();
91    
92    /* エディタの初期化 */
93    static void Shiki_editor_window_init(int argc, char **argv);
94    
95    /* バッファの内容を消去 */
96    static void clear_current_buffer_handler() {
97      Shiki_erase_buffer(Shiki_CURRENT_TEXT_BUFFER);
98    }
99    
100    static gboolean is_not_scheme_delimita_p(gunichar ch, gpointer user_data) {
101      return ch != '(' && ch != ')' &&  !g_unichar_isspace(ch);
102    }
103    
104    static gboolean is_double_quote(gunichar ch, gpointer user_data) {
105      return ch == '\"';
106    }
107    
108    static gboolean is_scheme_delimita_p(gunichar ch, gpointer user_data) {
109      return ch == ' ' || ch == '(' || ch == ')' || ch == '\"' || g_unichar_isspace(ch);
110    }
111    
112    /* ソースコードの色分け */
113    static void scheme_keyword_highlighting_current_buffer() {
114      GtkTextIter s, e;
115      HIGHILIGHT_COLOR c;
116      gchar *word;
117      gboolean is_comment, is_string;
118      gunichar ch;
119    
120      gtk_text_buffer_get_start_iter(Shiki_CURRENT_TEXT_BUFFER, &s);
121    
122      /* 簡単な Scheme レキシカルアナライザ */
123      while(TRUE) {
124        is_comment = FALSE;
125        is_string = FALSE;
126        if((ch = gtk_text_iter_get_char(&s)) != ';' && ch != '\"')
127          gtk_text_iter_forward_find_char(&s, is_not_scheme_delimita_p, NULL, NULL);
128        e = s;
129        if(gtk_text_iter_get_char(&s) == ';') {
130          gtk_text_iter_forward_line(&e);
131          gtk_text_iter_backward_char(&e);
132          is_comment = TRUE;
133        } else if(gtk_text_iter_get_char(&s) == '\"') {
134          while(TRUE) {
135            gtk_text_iter_forward_find_char(&e, is_double_quote, NULL, NULL);
136            gtk_text_iter_backward_char(&e);
137            if(gtk_text_iter_get_char(&e) != '\\') {
138              is_string = TRUE;
139              gtk_text_iter_forward_char(&e);
140              gtk_text_iter_forward_char(&e);
141              break;
142            }
143            gtk_text_iter_forward_char(&e);
144            gtk_text_iter_forward_char(&e);
145          }
146    
147    if(!filename) return FALSE;      } else
148    contents = get_all_buffer_contents(buffer);        gtk_text_iter_forward_find_char(&e, is_scheme_delimita_p, NULL, NULL);
149    text = g_locale_from_utf8(contents, -1, &br, &bw, &err);      
150    /* 文字列をファイルに保存 */      word = gtk_text_buffer_get_text(Shiki_CURRENT_TEXT_BUFFER, &s, &e, FALSE);
151    g_file_set_contents(filename, text, -1, NULL);  
152    gtk_text_buffer_set_modified(buffer, FALSE);      /* 対応する色をそれぞれトークン部分につける */
153    g_free(contents); g_free(text);      if(is_comment) /* コメント */
154    return TRUE;        gtk_text_buffer_apply_tag_by_name(Shiki_CURRENT_TEXT_BUFFER, "comment_highlighting", &s, &e);
155        else if(is_string) /* 文字列 */
156          gtk_text_buffer_apply_tag_by_name(Shiki_CURRENT_TEXT_BUFFER, "string_highlighting", &s, &e);    
157        else if(R5RS_KEYWORD_COLOR == (c = GPOINTER_TO_INT(g_hash_table_lookup(keywords_hash, word)))) /* R5RS キーワード */
158          gtk_text_buffer_apply_tag_by_name(Shiki_CURRENT_TEXT_BUFFER, "keyword_highlighting", &s, &e);
159        else if(R5RS_FUNCTION_COLOR == c) /* R5RS 関数 */
160          gtk_text_buffer_apply_tag_by_name(Shiki_CURRENT_TEXT_BUFFER, "function_highlighting", &s, &e);
161    
162        /* XXX : get_text() でいちいち文字列がアロケートされるから,非常に効率が悪いと思うけど… GtkTextBuffer から const gchar * が取れれば良いのに… */
163        g_free(word);
164    
165        if(gtk_text_iter_is_end(&e)) break;
166        s = e;
167      }
168  }  }
169    
170  /* ダイアログを開き,ファイル名を取得.msg はダイアログのメッセージ */  /* タブが切り替わる時のイベントハンドリング */
171  static gchar *get_filename_from_dialog(const gchar *msg) {  static void switch_tabpage_handler(GtkNotebook *notebook, GtkNotebookPage *page, guint pagenum) {
172      /* タブに対応する情報が格納された構造体を切替える */
173      Shiki_CURRENT_TAB_INFO = (ShikiBuffer *)g_list_nth_data(Shiki_EDITOR_BUFFER_LIST, pagenum);
174    
175    GtkWidget *dialog = gtk_file_selection_new(msg);    /* 現在のタブ番号を切替える */
176    int resp = gtk_dialog_run(GTK_DIALOG(dialog));    Shiki_CURRENT_TAB_NUM = pagenum;
   gchar *filename = NULL;  
177    
178    /* gtk_file_selection_get_filename が返す文字列定数は静的に確保されたバッファを指しているので,コピーしなければならない */    /* タブのラベルをウィンドウのタイトルに */
179    if(resp == GTK_RESPONSE_OK)    if(!Shiki_CURRENT_TAB_INFO) return;
180      filename = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(dialog)));    gtk_window_set_title (GTK_WINDOW(Shiki_EDITOR_WINDOW), Shiki_CURRENT_FILENAME);
181    
182    gtk_widget_destroy(dialog);    Shiki_update_modeline(Shiki_CURRENT_TEXT_BUFFER);  
   return filename;  
183  }  }
184    
185  /* 現在表示されているページのテキストバッファを取り出す */  /* GtkTextCharPredicate */
186  static GtkTextBuffer* get_text_buffer_from_current_tabpage(GtkNotebook* notebook) {  static gboolean is_kakko_or_kokka(gunichar ch, gpointer p) {
187    gint pagenum = gtk_notebook_get_current_page(notebook);    return ch == '(' || ch == ')';
   GtkScrolledWindow *scrolledwindow = GTK_SCROLLED_WINDOW(gtk_notebook_get_nth_page(notebook, pagenum));  
   /* GtkBin は一つしか子を持たない抽象コンテナクラス */  
   GtkTextView *view = GTK_TEXT_VIEW(gtk_bin_get_child(GTK_BIN(scrolledwindow)));  
   return gtk_text_view_get_buffer(view);  
188  }  }
189    static gboolean is_kakko(gunichar ch, gpointer p) {return ch == '(';}
190    static gboolean is_kokka(gunichar ch, gpointer p) {return ch == ')';}
191    
192  /* 現在表示されているタブが開いているファイルの名前を返す */  static gboolean search_sexp_kokka(GtkTextIter *end) {
193      gint nest_level = 0;
194    
195  /* 現在表示されているページの内容をファイルに保存 */    /* 対応する ')' を探す */
196  static void save_file_from_notebook(GtkNotebook *notebook) {    while(1) {
197    GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(notebook);      if(!gtk_text_iter_forward_find_char(end, is_kakko_or_kokka, NULL, NULL))
198    gchar *filename;        return FALSE;
   gint current_page;  
199    
200    /* 変更が無ければ何もしない */      if(gtk_text_iter_get_char(end) == '(')
201    if(!gtk_text_buffer_get_modified(buffer)) return;        nest_level++;
202        else {
203          if(!nest_level)
204            break;
205          else
206            nest_level--;
207        }
208      }
209      return TRUE;
210    }
211    
212    /* 現在表示されているタブが開いているファイルの名前を取得 */  /* カーソル以降の '(' に対応する ')' までの文字列 (S 式) を切り出す */
213    current_page = gtk_notebook_get_current_page(notebook);  static gboolean search_sexp(GtkTextIter *start, GtkTextIter *end) {
   filename = g_strdup(gtk_notebook_get_tab_label_text(notebook, gtk_notebook_get_nth_page(notebook, current_page)));  
214    
215    /* まだファイル名が設定されていなかったら,ダイアログを開いて入力させる */    /* カーソルの位置を取得 */
216    if(!filename || g_ascii_strcasecmp("*scratch*", filename) == 0) {    gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER, start, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
217      g_free(filename);  
218      if(!save_text_buffer(filename = get_filename_from_dialog("Save File As ..."), buffer))    if(gtk_text_iter_get_char(start) != '(')
219        return;      gtk_text_iter_forward_find_char(start, is_kakko, NULL, NULL);
220    } else  
221      save_text_buffer(filename, buffer);    *end = *start;
222    
223    gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook),    /* カーソル位置の前にある S 式を切り出す */
224        gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), current_page),    if(!search_sexp_kokka(end)) return FALSE;
225        filename);    gtk_text_iter_forward_char(end);
226    gtk_window_set_title (GTK_WINDOW (editor_window), filename);    return TRUE;
   g_free(filename);  
227  }  }
228    
229  /* ファイルを保存するイベントハンドラ */  /* ')' に対応する '(' までの文字列 (S 式) を切り出す */
230  static void save_file_handler(GtkWidget *widget, GtkWidget *notebook) {  static gboolean search_last_sexp_kakko(GtkTextIter *start) {
231    save_file_from_notebook(GTK_NOTEBOOK(notebook));    gint nest_level = 0;
232      /* ネストレベルを計算しながら ')' を探す */
233      while(1) {
234        if(!gtk_text_iter_backward_find_char(start, is_kakko_or_kokka, NULL, NULL))
235          return FALSE;
236    
237        if(gtk_text_iter_get_char(start) == ')')
238          nest_level++;
239        else {
240          if(!nest_level)
241            break;
242          else
243            nest_level--;
244        }
245      }
246      return TRUE;
247  }  }
248    
249  /* 現在表示されているページの内容をファイルに別名保存 */  /* カーソル以前の ')' に対応する '(' までの文字列 (S 式) を切り出す */
250  static void save_file_as_from_notebook(GtkNotebook *notebook) {  static gboolean search_last_sexp(GtkTextIter *start, GtkTextIter *end) {
   gint current_page;  
   GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(notebook);  
   gchar *filename = get_filename_from_dialog("Save File As ...");  
251    
252    if(!save_text_buffer(filename, buffer)) return;    /* カーソルの位置を取得 */
253      gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER, end, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
254    
255    current_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));    gtk_text_iter_backward_char(end);
   gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook),  
       gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), current_page),  
       filename);  
256    
257    gtk_window_set_title (GTK_WINDOW (editor_window), filename);    if(gtk_text_iter_get_char(end) != ')')
258        gtk_text_iter_backward_find_char(end, is_kokka, NULL, NULL);
259      *start = *end;
260      gtk_text_iter_forward_char(end);
261    
262    g_free(filename);    /* カーソル位置の前にある S 式を切り出す */
263  }    if(!search_last_sexp_kakko(start)) return FALSE;
264    
265  /* ファイルを別名保存するイベントハンドラ */    return TRUE;
 static void save_file_as_handler(GtkWidget *widget, GtkWidget *notebook) {  
   save_file_as_from_notebook(GTK_NOTEBOOK(notebook));  
266  }  }
267    
268  /* YES ボタン,NO ボタンそれぞれで呼ばれる callback */  /* キーが押された */
269  void really_quit_dialog_yes(GtkWidget *widget, gboolean *flag){*flag = FALSE;}  static gboolean signal_key_press_handler (GtkWidget *notebook, GdkEventKey *event, gpointer contextid) {
270  void really_quit_dialog_no(GtkWidget *widget, gint *flag){*flag = TRUE;}    GtkTextIter start, end;
271    
272  /* 本当に終了してもよろしいですか ? */    /* 括弧の対応の強調を無効に */
273  gboolean not_yet_save_changes_really_quit(GtkTextBuffer *buffer) {    gtk_text_buffer_get_start_iter(Shiki_CURRENT_TEXT_BUFFER, &start);
274    GtkWidget *yes_button, *no_button;    gtk_text_buffer_get_end_iter(Shiki_CURRENT_TEXT_BUFFER, &end);
275    static GtkWidget *dialog_window = NULL;    gtk_text_buffer_remove_tag_by_name(Shiki_CURRENT_TEXT_BUFFER, "parent_emphasis_background", &start, &end);
276    
277      if(event->state & GDK_CONTROL_MASK && event->state & GDK_MOD1_MASK) {
278        switch(event->keyval) {
279          case GDK_at : /* C-M-SPC */
280            { GtkTextIter start, end;
281              if(!search_sexp(&start, &end)) return FALSE;
282              gtk_text_buffer_select_range(Shiki_CURRENT_TEXT_BUFFER, &start, &end);
283            }
284            break;
285          case GDK_space : /* C-M-SPC */
286            { GtkTextIter start, end;
287              if(!search_last_sexp(&start, &end)) return FALSE;
288              gtk_text_buffer_select_range(Shiki_CURRENT_TEXT_BUFFER, &start, &end);
289            }
290            break;
291        }
292      } else if(event->state & GDK_CONTROL_MASK) {
293        switch(event->keyval) {
294          case GDK_f :  /* Ctrl + f : forward */
295            Shiki_forward_char();
296            break;
297          case GDK_b : /* Ctrl + b : backward */
298            Shiki_backward_char();
299            break;
300          case GDK_n : /* Ctrl + n : next line */
301            Shiki_forward_line(1);
302            break;
303          case GDK_p :  /* Ctrl + p : previous line */
304            Shiki_forward_line(-1);
305            break;
306          case GDK_h :
307            { GtkTextIter p;
308              gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
309              gtk_text_buffer_backspace(Shiki_CURRENT_TEXT_BUFFER, &p, FALSE, TRUE);
310            }
311            break;
312    
313    /* 変更が無ければそのまま終了 */        case GDK_e :  /* Ctrl + e : eval-expression */
314    if(!gtk_text_buffer_get_modified(buffer)) return FALSE;          Shiki_eval_expression();
315            break;
316    
317    if(dialog_window == NULL) {        case GDK_j :  /* Ctrl + j : eval-last-sexp */
318      gboolean flag = TRUE;          Shiki_eval_last_sexp();
319      dialog_window = gtk_dialog_new ();          break;
320    
321      /* 本当に終了してもよろしいですか ? ダイアログの初期化 */        case GDK_backslash : /* Ctrl + \ : Undo */
322      g_signal_connect(G_OBJECT(dialog_window), "delete_event", G_CALLBACK(gtk_false), NULL);          Shiki_undo();
323      g_signal_connect(G_OBJECT(dialog_window), "destroy", G_CALLBACK(gtk_main_quit), NULL);          break;
324    
325      gtk_window_set_title(GTK_WINDOW (dialog_window), "Really Quit ?");        case GDK_underscore : /* Ctrl + _ : Redo */
326      /* YES のボタン */          Shiki_redo();
327      yes_button = gtk_button_new_with_label("YES");          break;
     g_signal_connect(GTK_OBJECT(yes_button), "clicked", G_CALLBACK(really_quit_dialog_yes), &flag);  
     g_signal_connect_swapped(GTK_OBJECT(yes_button), "clicked", G_CALLBACK(gtk_widget_destroy), G_OBJECT(dialog_window));  
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_window)->action_area),  yes_button, TRUE, TRUE, 0);  
328    
329      /* NO のボタン */        case GDK_t : /* Ctrl + t : タブを開く */
330      no_button = gtk_button_new_with_label("NO");          append_default_tabpage_handler();
331      g_signal_connect(GTK_OBJECT(no_button), "clicked", G_CALLBACK(really_quit_dialog_no), &flag);          break;
     g_signal_connect_swapped(GTK_OBJECT(no_button), "clicked", G_CALLBACK(gtk_widget_destroy), G_OBJECT(dialog_window));  
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_window)->action_area),  no_button, TRUE, TRUE, 0);  
332    
333      gtk_window_set_modal(GTK_WINDOW(dialog_window), TRUE);        case GDK_k : /* Ctrl + k : タブを閉じる */
334      gtk_window_set_transient_for(GTK_WINDOW(dialog_window), GTK_WINDOW (editor_window));          kill_buffer_handler();
335            break;
336    
337      gtk_widget_show_all(dialog_window);        case GDK_w : /* Ctrl + w : カット */
338      gtk_main ();          gtk_text_buffer_cut_clipboard(Shiki_CURRENT_TEXT_BUFFER, Shiki_EDITOR_CLIPBOARD, TRUE);
339      dialog_window = NULL;          break;
340    
341      /* "delete_event" の返り値が FALSE ならば"destory" が発行され,window は破壊される */        case GDK_y : /* Ctrl + y : ヤンク */
342      return flag;          {GtkTextIter p;
343              gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
344              gtk_text_buffer_paste_clipboard(Shiki_CURRENT_TEXT_BUFFER, Shiki_EDITOR_CLIPBOARD, &p, TRUE);
345            }
346            break;        
347        }
348    }    }
349    return TRUE;    return FALSE;
350  }  }
351    
352  /* バッファがまだ保存されていないのに本当に終了するのかを尋ねる */  static void append_default_tabpage_handler() {
353  gboolean delete_event_handler(GtkWidget *widget, GdkEvent *event, GtkWidget *buffer){    Shiki_new_buffer_create(g_strdup("*scratch*"));
   return not_yet_save_changes_really_quit(GTK_TEXT_BUFFER(buffer));  
354  }  }
355    
356  /* 新しいバッファを作る */  /* ノートブックからタブとページ (バッファ) を削除 */
357  static GtkWidget *new_scrolled_text_buffer() {  static void kill_buffer_handler() {
358      Shiki_kill_buffer(Shiki_CURRENT_TEXT_BUFFER);
359    }
360    
361    GtkWidget *scrolledwindow, *view;  /* バッファをまるごとロード */
362    GtkTextBuffer *buffer;  static void load_buffer_by_gauche() {
363      GtkTextIter p;
364      gtk_text_buffer_get_end_iter(Shiki_CURRENT_TEXT_BUFFER, &p);
365      gtk_text_buffer_insert(Shiki_CURRENT_TEXT_BUFFER, &p, "\n\n", -1);
366      gtk_text_buffer_insert(Shiki_CURRENT_TEXT_BUFFER, &p, load_cstring_by_gauche(get_all_buffer_contents(Shiki_CURRENT_TEXT_BUFFER)), -1);
367    }
368    
   /* スクロールウィンドを作る */  
   scrolledwindow = gtk_scrolled_window_new(NULL, NULL);  
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);  
369    
   /* テキストビューワとバッファを作る */  
   view = gtk_text_view_new();  
   buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));  
   gtk_container_add(GTK_CONTAINER(scrolledwindow), view);  
   g_signal_connect(G_OBJECT(editor_window), "delete_event", G_CALLBACK(delete_event_handler), buffer);  
   gtk_widget_set_size_request(GTK_WIDGET(view), 500, 500);  
370    
371    /* 様々な初期化処理 */  /* ファイルをロード */
372      static void load_scheme_file_by_gauche() {
373    /* 括弧の強調表示のためのタグを作る */    const gchar *filename = Shiki_file_name_dialog("File Selection");
   gtk_text_buffer_create_tag (buffer, "parent_emphasis_background", "background", "green", NULL);  
374    
375    return scrolledwindow;    if(!filename) return;
376      Shiki_load_file(filename);
377  }  }
378    
379  /* ファイルを開く */  static gint compBuffer(gconstpointer a, gconstpointer b) {
380  static void open_file_from_notebook(GtkNotebook *notebook) {    return ((ShikiBuffer *)a)->text_buffer == b ? 0 : b - a;
381    gchar *contents, *text;  }
   gsize br, bw, len;  
   GError *err = NULL;  
382    
383    gchar *filename = get_filename_from_dialog("File Selection");  /* バッファに関連付けられたファイルをリロード.環境はクリアされる */
384    static void reload_buffer() {
385    #if 0
386      Shiki_CURRENT_BUFFER_ENV = Scm_MakeModule(NULL, FALSE);
387    
388    if(!filename) return;    /* xyzzy lisp 関数を登録 */
389      Scm_Init_xyzzylisp(SCM_MODULE(Shiki_CURRENT_BUFFER_ENV));
390      Scm_EvalCString("(set! *mode-line-format* (lambda () (format #f \"--~A- ~A (Gauche Interaction) [GtkDefault (utf8)]     L~S:~S             \" (if (buffer-modified-p) \"--\" \"**\") (buffer-name (selected-buffer)) (current-line-number) (current-column))))", Shiki_CURRENT_BUFFER_ENV);
391    #endif
392    
393    if(g_file_get_contents(filename, &contents, &len, NULL)) {    Shiki_load_file(Shiki_CURRENT_FILENAME);
     GtkTextBuffer *buffer;  
     GtkWidget *scrolledwindow;  
     GtkTextIter p;  
       
     /* 新しいバッファを開く */  
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook),  
                              scrolledwindow = new_scrolled_text_buffer(),  
                              gtk_label_new(filename));  
     buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_bin_get_child(GTK_BIN(scrolledwindow))));  
   
     if(!(text = g_locale_to_utf8(contents, -1, &br, &bw, &err)))  
       gtk_text_buffer_set_text(buffer, contents, len);  
     else  
       gtk_text_buffer_set_text(buffer, text, len);  
   
     /* バッファ未変更に */  
     gtk_text_buffer_set_modified(buffer, FALSE);  
     /* カーソル位置を先頭に */  
     gtk_text_buffer_get_start_iter(buffer, &p);  
     gtk_text_buffer_place_cursor(buffer, &p);  
     gtk_window_set_title (GTK_WINDOW (editor_window), filename);  
     gtk_widget_show_all(GTK_WIDGET(notebook));  
     g_free(contents); g_free(text); g_free(filename);  
   } else  
     g_printerr("Get file contents error !\n");  
394  }  }
395    
 /* ファイルを開くイベントハンドラ */  
 static void open_file_handler(GtkWidget *widget,  GtkWidget *notebook) {  
   open_file_from_notebook(GTK_NOTEBOOK(notebook));  
 }  
396    
397  /* gauche を起動して文字列を評価 */  /* gauche を起動して文字列をロード */
398  static gchar *eval_cstring_by_gauche(gchar *s) {  static gchar *load_cstring_by_gauche(gchar *s) {
399    gchar *msg;    gchar *msg;
400      gint result, i;
401    ScmObj result, error;    ScmEvalPacket packet;
402      /* 入力文字列ポートを開く */
403      ScmObj is = Scm_MakeInputStringPort(SCM_STRING(SCM_MAKE_STR_COPYING(s)), TRUE);
404    /* 出力文字列ポート開く */    /* 出力文字列ポート開く */
405    ScmObj os = Scm_MakeOutputStringPort(TRUE);    ScmObj os = Scm_MakeOutputStringPort(TRUE);
406    
407    /* Scheme レベルでエラーハンドリング */    Scm_Define(SCM_MODULE(Shiki_CURRENT_BUFFER_ENV), SCM_SYMBOL(SCM_INTERN("*input*")), is);
408    /* http://alohakun.blog7.fc2.com/blog-entry-517.html */    result = Scm_EvalCString("(load-from-port *input*)", SCM_OBJ(Shiki_CURRENT_BUFFER_ENV), &packet);
409    Scm_Define(Scm_UserModule(), SCM_SYMBOL(SCM_INTERN("*input*")), SCM_MAKE_STR(s));  
410    Scm_Define(Scm_UserModule(), SCM_SYMBOL(SCM_INTERN("*error*")), SCM_FALSE);    if(result == -1)
411        Scm_Write(packet.exception, os, SCM_WRITE_DISPLAY);
   result = Scm_EvalCString("(guard (e (else (set! *error* e) #f)) (eval (read-from-string *input*) (current-module)))", SCM_OBJ(Scm_UserModule()));  
   
   error = Scm_GlobalVariableRef(Scm_UserModule(), SCM_SYMBOL(SCM_INTERN("*error*")), 0);  
   
   /* 文字列を評価した結果をポートに書き込む */  
   if (!SCM_FALSEP(error))  
     Scm_Write(error, os, SCM_WRITE_DISPLAY);  
412    else    else
413      Scm_Write(result, os, SCM_WRITE_DISPLAY);      for(i = 0; i < packet.numResults; i++)
414          Scm_Printf(SCM_PORT(os), "%S\n", packet.results[i]);
415    
416    msg = Scm_GetString(SCM_STRING(Scm_GetOutputString(SCM_PORT(os))));    msg = Scm_GetString(SCM_STRING(Scm_GetOutputString(SCM_PORT(os))));
417    /* ポート閉じる */    /* ポート閉じる */
418      Scm_ClosePort(SCM_PORT(is));
419    Scm_ClosePort(SCM_PORT(os));    Scm_ClosePort(SCM_PORT(os));
420    
421    return msg;    return msg;
422  }  }
423    
424  /* 緑ボタンのハンドリング.バッファの選択されている S 式を評価 */  static void font_selection_ok(GtkWidget *button, GtkWidget *font_dialog) {
425  static void buffer_exec_handler(GtkWidget *widget,  GtkWidget *notebook) {    gchar *font_name = gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG (font_dialog));
426    GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook));    if(font_name) {
427        GtkRcStyle *style = gtk_rc_style_new ();
428        pango_font_description_free(style->font_desc);
429        style->font_desc = pango_font_description_from_string(font_name);
430        gtk_widget_modify_style (GTK_WIDGET(Shiki_CURRENT_TEXT_VIEW), style);
431        gtk_rc_style_unref (style);
432        g_free (font_name);
433      }
434    }
435    
436    GtkTextIter start, end, p;  /* フォントを選択させるイベントハンドラ */
437    gchar *code;  static void select_font(){
438    gtk_text_buffer_get_end_iter(buffer, &p);    GtkWidget *font_dialog = gtk_font_selection_dialog_new("Font Selection Dialog");
439    gtk_text_buffer_insert(buffer, &p, "\n\n", -1);    g_signal_connect (GTK_FONT_SELECTION_DIALOG (font_dialog)->ok_button, "clicked", G_CALLBACK(font_selection_ok), font_dialog);
440      gtk_dialog_run(GTK_DIALOG(font_dialog));
441      gtk_widget_destroy(font_dialog);
442    }
443    
444    /* このアプリケーションについて */
445    static void about_this_application() {
446      GtkAboutDialog *about = GTK_ABOUT_DIALOG(gtk_about_dialog_new());
447      const gchar *authors[] = {
448        "若槻俊宏 (あろは) <alohakun@gmail.com>\n",
449        "Contribute : tkng さん",
450        "(http://d.hatena.ne.jp/tkng/20061113)", NULL
451      };
452      gtk_about_dialog_set_authors(about, authors);
453      gtk_about_dialog_set_copyright(about, "Copyright(C)2006  WAKATSUKI Toshihiro");
454      gtk_about_dialog_set_name(about, "式 (SHIKI)");
455      gtk_about_dialog_set_website_label(about, "本当に30日でエディタが出来上がるのかを試してみるBlog");
456      gtk_about_dialog_set_website(about, "http://alohakun.blog7.fc2.com/blog-category-29.html");
457      gtk_dialog_run(GTK_DIALOG(about));
458      gtk_widget_destroy(GTK_WIDGET(about));
459    }
460    
461    #if 0
462    /* 開発途中に使用したダミーイベントハンドラー */
463    static void dummy_handler() {
464      GtkWidget *dummy = gtk_message_dialog_new(GTK_WINDOW(Shiki_EDITOR_WINDOW),
465          GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE,
466          "Sorry... This Button is Dummy.");
467      gtk_dialog_run(GTK_DIALOG(dummy));
468      gtk_widget_destroy(dummy);
469    }
470    #endif
471    
472    /* マウスで選択されている範囲の文字列を取得 */  /* テキストバッファから全ての文字列を取り出す */
473    if(gtk_text_buffer_get_selection_bounds(buffer, &start, &end)) {  static gchar* get_all_buffer_contents(GtkTextBuffer *buffer) {
474      code = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);    GtkTextIter start, end;
475      gtk_text_buffer_insert(buffer, &p, eval_cstring_by_gauche(code), -1);    gtk_text_buffer_get_start_iter(buffer, &start);
476      g_free(code);    gtk_text_buffer_get_end_iter(buffer, &end);
477    }    return gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
478    }
479    
480    /* buffer の内容をファイル filename に保存 */
481    static gboolean save_text_buffer(const gchar *filename, GtkTextBuffer *buffer) {
482      gchar *contents, *text;
483      gsize br, bw;
484      GError *err = NULL;
485    
486      if(!filename) return FALSE;
487      contents = get_all_buffer_contents(buffer);
488      text = g_locale_from_utf8(contents, -1, &br, &bw, &err);
489      /* 文字列をファイルに保存 */
490      g_file_set_contents(filename, text, -1, NULL);
491      gtk_text_buffer_set_modified(buffer, FALSE);
492      Shiki_update_modeline(Shiki_CURRENT_TEXT_BUFFER);
493      g_free(contents); g_free(text);
494      return TRUE;
495  }  }
496    
497  // GtkTextCharPredicate  /* 現在表示されているページの内容をファイルに保存 */
498  static gboolean is_kakko_or_kokka(gunichar ch, gpointer p) {  static void save_file() {
499    return ch == '(' || ch == ')';  
500      /* *help* *scratch* などへの変更は保存しない */
501      if(Shiki_CURRENT_TAB_TITLE[0] == '*') return;
502    
503      /* 変更が無ければ何もしない */
504      if(!gtk_text_buffer_get_modified(Shiki_CURRENT_TEXT_BUFFER)) return;
505    
506      /* まだファイル名が設定されていなかったら,ダイアログを開いて入力させる */
507      if(strcmp("*scratch*", Shiki_CURRENT_FILENAME) == 0) {
508        const gchar *filename = Shiki_file_name_dialog("Save File As ...");
509        if(!filename) return;
510        if(!save_text_buffer(filename, Shiki_CURRENT_TEXT_BUFFER)) return;
511        gtk_notebook_set_tab_label_text(Shiki_EDITOR_NOTEBOOK, GTK_WIDGET(Shiki_CURRENT_TAB), filename);
512        gtk_window_set_title (GTK_WINDOW(Shiki_EDITOR_WINDOW), filename);
513      } else
514        save_text_buffer(Shiki_CURRENT_TAB_TITLE, Shiki_CURRENT_TEXT_BUFFER);
515  }  }
 static gboolean is_kokka(gunichar ch, gpointer p) {return ch == ')';}  
516    
517    /* 現在表示されているページの内容をファイルに別名保存 */
518    static void save_file_as() {
519      const gchar *filename = Shiki_file_name_dialog("Save File As ...");
520    
521  /* ')' に対応する '(' までの文字列 (S 式) を切り出す */    if(!filename) return;
522  static gboolean search_sexp_string(GtkTextIter *start) {    if(!save_text_buffer(filename, Shiki_CURRENT_TEXT_BUFFER)) return;
   gint nest_level = 0;  
   /* カーソル位置の前にある S 式を切り出す */  
   while(1) {  
     if(!gtk_text_iter_backward_find_char(start, is_kakko_or_kokka, NULL, NULL))  
       return FALSE;  
523    
524      if(gtk_text_iter_get_char(start) == ')')    gtk_notebook_set_tab_label_text(Shiki_EDITOR_NOTEBOOK, GTK_WIDGET(Shiki_CURRENT_TAB), filename);
525        nest_level++;    gtk_window_set_title (GTK_WINDOW (Shiki_EDITOR_WINDOW), filename);
526      else {  }
527        if(!nest_level)  
528          break;  /* 緑ボタンのハンドリング.バッファの選択範囲の S 式をロード (逐次評価) */
529        else  static void load_region_by_gauche() {
530          nest_level--;  
531      }    GtkTextIter start, end, p;
532      gchar *code;
533      gtk_text_buffer_get_end_iter(Shiki_CURRENT_TEXT_BUFFER, &p);
534      gtk_text_buffer_insert(Shiki_CURRENT_TEXT_BUFFER, &p, "\n\n", -1);
535    
536      /* マウスで選択されている範囲の文字列を取得 */
537      if(gtk_text_buffer_get_selection_bounds(Shiki_CURRENT_TEXT_BUFFER, &start, &end)) {
538        code = gtk_text_buffer_get_text(Shiki_CURRENT_TEXT_BUFFER, &start, &end, FALSE);
539        gtk_text_buffer_insert(Shiki_CURRENT_TEXT_BUFFER, &p, load_cstring_by_gauche(code), -1);
540        g_free(code);
541    }    }
   return TRUE;  
542  }  }
543    
544  /* カーソル位置のネストレベルを返す */  /* カーソル位置のネストレベルを返す */
# Line 355  static gint get_parent_nest_level_at_cur Line 563  static gint get_parent_nest_level_at_cur
563    }    }
564  }  }
565    
 /* タブが切り替わる時のイベントハンドリング */  
 static void switch_page(GtkNotebook *notebook, GtkNotebookPage *page, guint pagenum, gpointer p) {  
   /* タブのラベルをウィンドウのタイトルに */  
   gtk_window_set_title (GTK_WINDOW(editor_window), gtk_notebook_get_tab_label_text(notebook, GTK_WIDGET(gtk_notebook_get_nth_page(notebook, pagenum))));  
 }  
   
566  /* ページのタブと境界線を on/off */  /* ページのタブと境界線を on/off */
567  static void tabsborder_on_off(GtkButton *button, GtkNotebook *notebook) {  static void tabsborder_on_off(GtkButton *button, GtkNotebook *notebook) {
568    gint tval = FALSE;    gint tval = FALSE;
# Line 374  static void tabsborder_on_off(GtkButton Line 576  static void tabsborder_on_off(GtkButton
576    gtk_notebook_set_show_border(notebook, bval);    gtk_notebook_set_show_border(notebook, bval);
577  }  }
578    
 /* ノートブックからページを削除 */  
 static void remove_tabpage(GtkNotebook *notebook) {  
   GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(notebook);  
   if(!not_yet_save_changes_really_quit(buffer)) {  
     gint page = gtk_notebook_get_current_page(notebook);  
     gtk_notebook_remove_page(notebook, page);  
     /* ウィジットを強制的に再描画 */  
     gtk_widget_queue_draw(GTK_WIDGET(notebook));  
   }  
 }  
   
 static void remove_tabpage_handler(GtkButton *button, GtkWidget *notebook) {  
   remove_tabpage(GTK_NOTEBOOK(notebook));  
 }  
   
 /* ノートブックの末尾にページを追加 */  
 static void append_tabpage(GtkButton *button, GtkNotebook *notebook) {  
   gtk_notebook_append_page(notebook, new_scrolled_text_buffer(), gtk_label_new("*scratch*"));  
   gtk_widget_show_all(GTK_WIDGET(notebook));  
 }  
   
579  /* タブの位置を調整 */  /* タブの位置を調整 */
580  static void rotate_tab_position(GtkButton   *button, GtkNotebook *notebook ) {  static void rotate_tab_position(GtkButton *button, GtkNotebook *notebook ) {
581    gtk_notebook_set_tab_pos(notebook, (notebook->tab_pos + 1) % 4);    gtk_notebook_set_tab_pos(notebook, (notebook->tab_pos + 1) % 4);
582  }  }
583    
 /* 特定のキー操作のハンドリング */  
   
 /* キーが押された */  
 static gboolean signal_key_press_handler (GtkWidget *notebook, GdkEventKey *event, gpointer p) {  
   GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook));  
   
   GtkTextIter start, end;  
   
   /* 括弧の対応の強調を無効に */  
   gtk_text_buffer_get_start_iter(buffer, &start);  
   gtk_text_buffer_get_end_iter(buffer, &end);  
   gtk_text_buffer_remove_tag_by_name(buffer, "parent_emphasis_background", &start, &end);  
   
   /* Ctrl + j : カーソル手前の S 式の評価 */  
   if(event->keyval == GDK_j && event->state & GDK_CONTROL_MASK) {  
     gchar *code;  
     GtkTextIter start, end;  
   
     /* カーソルの位置を取得 */  
     gtk_text_buffer_get_iter_at_mark(buffer, &end, gtk_text_buffer_get_insert(buffer));  
   
     gtk_text_iter_backward_find_char(&end, is_kokka, NULL, NULL);  
     start = end;  
     gtk_text_iter_forward_char(&end);  
   
     /* カーソル位置の前にある S 式を切り出す */  
     if(!search_sexp_string(&start)) return FALSE;  
   
     code = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);  
     gtk_text_buffer_insert(buffer, &end, "\n\n", -1);  
     gtk_text_buffer_insert(buffer, &end, eval_cstring_by_gauche(code), -1);  
     g_free(code);  
   }  
   
   /* Ctrl + O : ファイル開く */  
   if(event->keyval == GDK_O && event->state & GDK_CONTROL_MASK) {  
     open_file_from_notebook(GTK_NOTEBOOK(notebook));      
   }  
   
   /* Ctrl + s : ファイル保存 */  
   if(event->keyval == GDK_s && event->state & GDK_CONTROL_MASK) {  
     save_file_from_notebook(GTK_NOTEBOOK(notebook));      
   }  
   
   /* Ctrl + w : ファイル別名保存 */  
   if(event->keyval == GDK_w && event->state & GDK_CONTROL_MASK) {  
     save_file_as_from_notebook(GTK_NOTEBOOK(notebook));      
   }  
     
   /* Ctrl + t : タブを開く */  
   if(event->keyval == GDK_t && event->state & GDK_CONTROL_MASK) {  
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), new_scrolled_text_buffer(), gtk_label_new("*scratch*"));  
     gtk_widget_show_all(GTK_WIDGET(notebook));  
   }  
   
   /* Ctrl + c : タブを閉じる */  
   if(event->keyval == GDK_C && event->state & GDK_CONTROL_MASK) {  
     remove_tabpage(GTK_NOTEBOOK(notebook));  
   }  
   
   /* Ctrl + q : 終了 */  
   if(event->keyval == GDK_q && event->state & GDK_CONTROL_MASK) {  
     /* "delete-event" を発生させる.ウィンドウの × ボタンが押されたのと同じ */  
     GdkEvent ev;  
   
     ev.any.type = GDK_DELETE;  
     ev.any.window = editor_window->window;  
     ev.any.send_event = FALSE;  
     gdk_event_put (&ev);  
   }  
   
   return FALSE;  
 }  
   
584  /* キーが離された */  /* キーが離された */
585  static gboolean signal_key_release_handler (GtkWidget *notebook, GdkEventKey *event, gpointer p) {  static gboolean signal_key_release_handler (GtkWidget *notebook, GdkEventKey *event, gpointer contextid) {
586      static gint metakey_pressed = 0;
587    GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook));    static gint controlx_pressed = 0;
588    
589    if(event->keyval == GDK_parenright && event->state & GDK_SHIFT_MASK) {    if(event->keyval == GDK_parenright && event->state & GDK_SHIFT_MASK) {
590      GtkTextIter start, end;      GtkTextIter start, end;
591    
592      /* カーソルの位置を取得 */      /* カーソルの位置を取得 */
593      gtk_text_buffer_get_iter_at_mark(buffer, &end, gtk_text_buffer_get_insert(buffer));      gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER, &end, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
594    
595      start = end;      start = end;
596      gtk_text_iter_backward_char(&start);      gtk_text_iter_backward_char(&start);
597    
598      /* カーソル位置の前にある S 式を切り出す */      /* カーソル位置の前にある S 式を切り出す */
599      if(!search_sexp_string(&start)) return FALSE;      if(!search_last_sexp_kakko(&start)) return FALSE;
600    
601      gtk_text_buffer_apply_tag_by_name(buffer, "parent_emphasis_background", &start, &end);      gtk_text_buffer_apply_tag_by_name(Shiki_CURRENT_TEXT_BUFFER, "parent_emphasis_background", &start, &end);
602    }    }
603    
604    /* 改行されるたびに,自動的に括弧のネストの深さに応じた数のスペース (インデント) が行頭に入る */    /* 改行されるたびに,自動的に括弧のネストの深さに応じた数のスペース (インデント) が行頭に入る */
605    if(event->keyval == GDK_Return) {    if(event->keyval == GDK_Return) {
606      gint indentWidth = get_parent_nest_level_at_cursor(buffer) * INDENT_WIDTH;      gint indentWidth = get_parent_nest_level_at_cursor(Shiki_CURRENT_TEXT_BUFFER) * SCM_INT_VALUE(Scm_GlobalVariableRef(SCM_MODULE(Shiki_CURRENT_BUFFER_ENV), SCM_SYMBOL(SCM_INTERN("*indent-width*")), 0)), i;
607      gchar *indent = g_strnfill(indentWidth, ' ');      static gchar *indent = " ";
608      gtk_text_buffer_insert_at_cursor(buffer, indent, -1);      for(i = 0; i < indentWidth; i++)
609      g_free(indent);        gtk_text_buffer_insert_at_cursor(Shiki_CURRENT_TEXT_BUFFER, indent, -1);
610    }    }
611    
612      /* C-x */
613      if(event->keyval == GDK_x && event->state & GDK_CONTROL_MASK) {
614        controlx_pressed++;
615        gtk_statusbar_push(GTK_STATUSBAR(Shiki_EDITOR_STATUSBAR), GPOINTER_TO_INT(contextid), "C-x -");
616      } else if(event->state & GDK_CONTROL_MASK) {
617    
618        if(controlx_pressed > 0) {
619          switch(event->keyval) {
620            case GDK_c :/* C-x C-c : 終了 */
621              gtk_statusbar_push(GTK_STATUSBAR(Shiki_EDITOR_STATUSBAR), GPOINTER_TO_INT(contextid), "C-c");
622              {/* "delete-event" を発生させる.ウィンドウの × ボタンが押されたのと同じ */
623                GdkEvent ev;
624    
625                ev.any.type = GDK_DELETE;
626                ev.any.window = Shiki_EDITOR_WINDOW->window;
627                ev.any.send_event = FALSE;
628                gdk_event_put (&ev);
629              }
630              break;
631    
632            case GDK_f : /* C-x C-f : ファイル開く */
633              gtk_statusbar_push(GTK_STATUSBAR(Shiki_EDITOR_STATUSBAR), GPOINTER_TO_INT(contextid), "C-f");
634              Shiki_open_file_dialog();
635              break;
636    
637            case GDK_s : /* C-x C-s : ファイル保存 */
638              gtk_statusbar_push(GTK_STATUSBAR(Shiki_EDITOR_STATUSBAR), GPOINTER_TO_INT(contextid), "C-s");
639              save_file();    
640              break;
641    
642            case GDK_w : /* C-x C-w : ファイル別名保存 */
643              gtk_statusbar_push(GTK_STATUSBAR(Shiki_EDITOR_STATUSBAR), GPOINTER_TO_INT(contextid), "C-w");
644              save_file_as();    
645              break;
646          }
647          controlx_pressed = 0;
648        }
649    
650        switch(event->keyval) {
651          case GDK_g :/* C-g : キャンセル */
652            metakey_pressed = 0;
653            controlx_pressed = 0;
654    
655            gtk_statusbar_push(GTK_STATUSBAR(Shiki_EDITOR_STATUSBAR), GPOINTER_TO_INT(contextid), "Quit");
656            break;
657        }
658    
659      }
660    return FALSE;    return FALSE;
661  }  }
662    static void open_online_help() {
663      GtkTextIter p;
664      Shiki_new_buffer_create(g_strdup("*help*"));
665      gtk_text_buffer_set_text(Shiki_CURRENT_TEXT_BUFFER,
666          "コマンドラインからの起動方法\n"
667          "$ ./shiki [file1 file2 ....]\n\n"
668          "[フォルダのアイコン]             ファイルを開く (C-x C-f)\n"
669          "[フロッピーディスクのアイコン]   バッファを保存 (C-x C-s)\n"
670          "[フロッピーとえんぴつのアイコン] バッファを別名保存 (C-x C-w)\n"
671          "[ギアのアイコン]                 選択領域を gauche にロード\n"
672          "[新規アイコン]                   新規バッファを開く (C-t)\n"
673          "[左向き矢印アイコン]             やり直し (Undo) (C-\\)\n"
674          "[右向き矢印アイコン]             再試行   (Redo) (C-_)\n"
675          "[ルーペ]                         検索\n"
676          "[ルーペとペン]                   置換\n"
677          "[ゴミ箱アイコン]                 バッファをクリア\n"
678          "\n"
679          "(注 : 通常,バッファの内容が失われる恐れがあるときには警告しますが,クリアだけは警告をしません.もし間違って消してしまった場合には慌てずに Undo してください)\n"
680          "\n"
681          "[× アイコン]                     バッファを閉じる (C-k)\n"
682          "[A アイコン]                     フォントの選択\n"
683          "[顔みたいなアイコン]             Scheme ファイルのロード\n"
684          "[緑っぽい,変換アイコン]         バッファの内容を全てロード\n"
685          "[Abc]                            シンタックスハイライティング\n"
686          "[ヘルプ (?) アイコン]            このヘルプ画面を表示します\n"
687          "[A]                              フォントの選択\n"
688          "[マーキング (ちょん) のアイコン] タブの on/off\n"
689          "[工具 (スパナ) のアイコン]       タブの位置の調整\n"
690          "[info アイコン]                  このアプリケーションについての情報\n"
691          "\n"
692          "C-f : → に移動 (forward)\n"
693          "C-b : ← に移動 (backward)\n"
694          "C-n : ↓ に移動 (next line)\n"
695          "C-p : ↑ に移動 (previous line)\n"
696          "\n"
697          "C-h : バックスペース\n"
698          "C-w : カット\n"
699          "C-y : ヤンク (ペースト)\n"
700          "C-\\ : Undo\n"
701          "C-_ : Redo\n"
702          "\n"
703          "C-e : カーソル後ろの S 式を評価 (eval-expression)\n"
704          "C-j : カーソル手前の S 式を評価 (eval-last-sexp)\n"
705          "(emacs/xyzzy の *scratch* バッファと同じ)\n"
706          "\n"
707          "C-M-@ : カーソル以降の S 式を選択 (mark-sexp)\n"
708          "C-M-SPC : カーソル手前の S 式を選択 (mark-last-sexp)\n"
709          "C-x C-c : 終了.ウィンドウの × ボタンを押したのと同じ\n"
710          , -1);
711      gtk_text_buffer_set_modified(Shiki_CURRENT_TEXT_BUFFER, FALSE);
712      /* カーソル位置を先頭に */
713      gtk_text_buffer_get_start_iter(Shiki_CURRENT_TEXT_BUFFER, &p);
714      gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p);    
715      gtk_text_view_set_editable(Shiki_CURRENT_TEXT_VIEW, FALSE);
716    }
717    
718  /* エディタの編集画面の初期化 */  /* エディタの編集画面の初期化 */
719  static void editor_window_init() {  static void Shiki_editor_window_init(int argc, char **argv) {
720    GtkWidget *vbox, *toolbar, *notebook;    GtkWidget *vbox, *toolbar, *modeline_bg = gtk_event_box_new();
721    GtkToolItem *icon;    GtkToolItem *icon;
722    GtkIconSize iconsize;    GtkIconSize iconsize;
723      GtkTooltips *toolbar_tips = gtk_tooltips_new();
724    /* 「開く」「保存」「別名保存」「選択領域を実行」アイコン */    /* 「開く」「保存」「別名保存」「選択領域を実行」アイコン */
725    GtkToolItem *oicon, *sicon, *saicon, *eicon;    GtkToolItem *oicon, *sicon, *saicon, *eicon;
726    
727      gint contextid, i;
728    
729      /* ハイライティングキーワードのハッシュテーブルを初期化 */
730      keywords_hash = g_hash_table_new(g_str_hash, g_str_equal);
731      i = 0;
732      while(R5RS_keywords[i] != NULL)
733        g_hash_table_insert(keywords_hash, R5RS_keywords[i++], GINT_TO_POINTER(R5RS_KEYWORD_COLOR));
734      i = 0;
735      while(R5RS_functions[i] != NULL)
736        g_hash_table_insert(keywords_hash, R5RS_functions[i++], GINT_TO_POINTER(R5RS_FUNCTION_COLOR));
737    
738    /* 窓を作る */    /* 窓を作る */
739    editor_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);    Shiki_EDITOR_WINDOW = gtk_window_new(GTK_WINDOW_TOPLEVEL);
740    g_signal_connect(G_OBJECT(editor_window), "destroy", G_CALLBACK(gtk_main_quit), NULL);    g_signal_connect(G_OBJECT(Shiki_EDITOR_WINDOW), "destroy", G_CALLBACK(gtk_main_quit), NULL);
741    
742      /* システムのデフォルトクリップボードを取得 */
743      Shiki_EDITOR_CLIPBOARD = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
744    
745    /* パッキングボックスを作る */    /* パッキングボックスを作る */
746    vbox = gtk_vbox_new(FALSE, 0);    vbox = gtk_vbox_new(FALSE, 0);
# Line 523  static void editor_window_init() { Line 748  static void editor_window_init() {
748    toolbar = gtk_toolbar_new();    toolbar = gtk_toolbar_new();
749    gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);    gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
750    
751    notebook = gtk_notebook_new();    Shiki_EDITOR_NOTEBOOK = GTK_NOTEBOOK(gtk_notebook_new());
752    g_signal_connect(G_OBJECT(notebook), "switch-page", GTK_SIGNAL_FUNC(switch_page), NULL);    g_signal_connect(G_OBJECT(Shiki_EDITOR_NOTEBOOK), "switch-page", GTK_SIGNAL_FUNC(switch_tabpage_handler), NULL);
753    
754    /* ツールバーに付けるアイコンの設定 */    /* ツールバーに付けるアイコンの設定 */
755    gtk_toolbar_set_style(GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);    gtk_toolbar_set_style(GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
# Line 533  static void editor_window_init() { Line 758  static void editor_window_init() {
758    /* アイコン作る */    /* アイコン作る */
759    
760    /* ファイル開く */    /* ファイル開く */
761    oicon = gtk_tool_button_new(gtk_image_new_from_stock ("gtk-open", iconsize), "");    oicon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_OPEN, iconsize), "");
762    /* 「開く」ボタンにファイルを読み込むアクションを関連付ける */    /* 「開く」ボタンにファイルを読み込むアクションを関連付ける */
763    g_signal_connect(G_OBJECT(oicon), "clicked", G_CALLBACK(open_file_handler), G_OBJECT(notebook));    g_signal_connect(G_OBJECT(oicon), "clicked", G_CALLBACK(Shiki_open_file_dialog), NULL);
764    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(oicon));    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(oicon));
765      gtk_tool_item_set_tooltip(oicon, toolbar_tips, "ファイルを開きます",
766          "新しいバッファを開いて,そこにファイルの内容を展開します.");
767    
768    /* バッファ保存 */    /* バッファ保存 */
769    sicon = gtk_tool_button_new(gtk_image_new_from_stock ("gtk-save", iconsize), "");    sicon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_SAVE, iconsize), "");
770    /* 「保存」ボタンにファイルを書き出すアクションを関連付ける */    /* 「保存」ボタンにファイルを書き出すアクションを関連付ける */
771    g_signal_connect(G_OBJECT(sicon), "clicked", G_CALLBACK(save_file_handler), G_OBJECT(notebook));    g_signal_connect(G_OBJECT(sicon), "clicked", G_CALLBACK(save_file), NULL);
772    gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET(sicon));          gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET(sicon));      
773      gtk_tool_item_set_tooltip(sicon, toolbar_tips, "バッファを保存します",
774          "バッファにファイル名が設定されていない場合には,ダイアログを開いてファイル名を取得します");
775    
776    /* バッファを別名保存 */    /* バッファを別名保存 */
777    saicon = gtk_tool_button_new(gtk_image_new_from_stock ("gtk-save-as", iconsize), "");    saicon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, iconsize), "");
778    /* 「別名保存」ボタンに別名のファイル開いて内容を書き出すアクションを関連付ける */    /* 「別名保存」ボタンに別名のファイル開いて内容を書き出すアクションを関連付ける */
779    g_signal_connect(G_OBJECT(saicon), "clicked", G_CALLBACK(save_file_as_handler), G_OBJECT(notebook));    g_signal_connect(G_OBJECT(saicon), "clicked", G_CALLBACK(save_file_as), NULL);
   
780    gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET(saicon));    gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET(saicon));
781      gtk_tool_item_set_tooltip(saicon, toolbar_tips, "バッファを別名保存します",
782          "");
783    
784    /* バッファ実行 */    /* バッファ実行 */
785    eicon = gtk_tool_button_new(gtk_image_new_from_stock ("gtk-execute", iconsize), "");    eicon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_EXECUTE, iconsize), "");
786    /* バッファを実行ボタンに libgauche を関連付ける */    /* 「選択範囲をロード」ボタンに libgauche を関連付ける */
787    g_signal_connect(G_OBJECT(eicon), "clicked", G_CALLBACK(buffer_exec_handler), G_OBJECT(notebook));    g_signal_connect(G_OBJECT(eicon), "clicked", G_CALLBACK(load_region_by_gauche), NULL);
788    gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET(eicon));    gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET(eicon));
789      gtk_tool_item_set_tooltip(eicon, toolbar_tips, "選択範囲の S 式をロードします (load-region-lisp)",
790          "Scheme (gauche) で評価できる S 式を評価します.");
791    
792    /* キーバインドのハンドリングを登録 */    gtk_container_add(GTK_CONTAINER(Shiki_EDITOR_WINDOW), vbox);
793    g_signal_connect(G_OBJECT(notebook), "key-press-event", G_CALLBACK (signal_key_press_handler), NULL);    gtk_container_add(GTK_CONTAINER(vbox), GTK_WIDGET(Shiki_EDITOR_NOTEBOOK));
   g_signal_connect(G_OBJECT(notebook), "key-release-event", G_CALLBACK (signal_key_release_handler), NULL);  
   gtk_container_add(GTK_CONTAINER(editor_window), vbox);  
   gtk_container_add(GTK_CONTAINER(vbox), notebook);  
794    
795    /* デフォルトのページを追加 */    icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_NEW, iconsize), "");
796    gtk_notebook_prepend_page(GTK_NOTEBOOK(notebook),    g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(append_default_tabpage_handler), NULL);
797        new_scrolled_text_buffer(),    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
798        gtk_label_new("*scratch*"));    gtk_tool_item_set_tooltip(icon, toolbar_tips, "新規バッファを開きます", "");
799    
800    /* タブの on/off */    icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_UNDO, iconsize), "");
801    icon = gtk_tool_button_new(gtk_image_new_from_stock ("gtk-apply", iconsize), "append");    g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(Shiki_undo), NULL);
   g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(tabsborder_on_off), G_OBJECT(notebook));  
802    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
803      gtk_tool_item_set_tooltip(icon, toolbar_tips, "Undo","");
804    
805    /* タブの位置 */    icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_REDO, iconsize), "");
806    icon = gtk_tool_button_new(gtk_image_new_from_stock ("gtk-preferences", iconsize), "append");    g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(Shiki_redo), NULL);
   g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(rotate_tab_position), G_OBJECT( notebook));  
807    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
808      gtk_tool_item_set_tooltip(icon, toolbar_tips, "Redo", "");
809    
810    /* タブを追加 */    icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_FIND, iconsize), "");
811    icon = gtk_tool_button_new(gtk_image_new_from_stock ("gtk-add", iconsize), "append");    g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(Shiki_search_buffer), NULL);
   g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(append_tabpage), G_OBJECT( notebook));  
812    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
813      gtk_tool_item_set_tooltip(icon, toolbar_tips, "検索", "");
814    
815    /* 選択されているページを取り除く */  
816    icon = gtk_tool_button_new(gtk_image_new_from_stock ("gtk-close", iconsize), "remove");    icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_FIND_AND_REPLACE, iconsize), "");
817    g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(remove_tabpage_handler), G_OBJECT( notebook));    g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(Shiki_replace_buffer), NULL);
818    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));    gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
819      gtk_tool_item_set_tooltip(icon, toolbar_tips, "置換", "");
820    
821      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_REFRESH, iconsize), "");
822      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(reload_buffer), NULL);
823      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
824      gtk_tool_item_set_tooltip(icon, toolbar_tips, "リロード", "環境はクリアされます");
825    
826      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_DELETE, iconsize), "");
827      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(clear_current_buffer_handler), NULL);
828      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
829      gtk_tool_item_set_tooltip(icon, toolbar_tips, "バッファの内容を全消去",
830          "まだ内容が保存されていない場合でも警告しません");
831    
832      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_CLOSE, iconsize), "");
833      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(kill_buffer_handler), NULL);
834      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
835      gtk_tool_item_set_tooltip(icon, toolbar_tips, "バッファを閉じます",
836          "まだ内容が保存されていない場合は警告します");
837    
838      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_CONNECT, iconsize), "");
839      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(load_scheme_file_by_gauche), NULL);
840      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
841      gtk_tool_item_set_tooltip(icon, toolbar_tips, "Scheme ファイルをロード", "");
842    
843      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_CONVERT, iconsize), "");
844      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(load_buffer_by_gauche), G_OBJECT(Shiki_EDITOR_NOTEBOOK));
845      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
846      gtk_tool_item_set_tooltip(icon, toolbar_tips, "バッファをロード", "");
847    
848      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_SPELL_CHECK, iconsize), "");
849      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(scheme_keyword_highlighting_current_buffer), NULL);
850      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
851      gtk_tool_item_set_tooltip(icon, toolbar_tips, "シンタックスハイライティング", "");
852    
853    
854      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, iconsize), "");
855      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(open_online_help), NULL);
856      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
857      gtk_tool_item_set_tooltip(icon, toolbar_tips, "ヘルプ", "");
858    
859      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_BOLD, iconsize), "");
860      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(select_font), NULL);
861      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
862      gtk_tool_item_set_tooltip(icon, toolbar_tips, "フォントの変更", "");
863    
864      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_APPLY, iconsize), "");
865      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(tabsborder_on_off), G_OBJECT(Shiki_EDITOR_NOTEBOOK));
866      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
867      gtk_tool_item_set_tooltip(icon, toolbar_tips, "タブの on/off", "");
868    
869      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_PREFERENCES, iconsize), "");
870      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(rotate_tab_position), G_OBJECT(Shiki_EDITOR_NOTEBOOK));
871      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
872      gtk_tool_item_set_tooltip(icon, toolbar_tips, "タブ位置の設定", "");
873    
874      icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, iconsize), "");
875      g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(about_this_application), NULL);
876      gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon));
877      gtk_tool_item_set_tooltip(icon, toolbar_tips, "このアプリケーションについて", "");
878    
879      /* モードライン作る */
880      Shiki_EDITOR_MODELINE_LABEL = gtk_label_new(NULL);
881      gtk_container_add(GTK_CONTAINER (modeline_bg), Shiki_EDITOR_MODELINE_LABEL);
882    
883      gdk_color_parse("black", &COLOR_BLACK);
884      gdk_color_parse("green", &COLOR_GREEN);
885    
886      gtk_widget_modify_fg(Shiki_EDITOR_MODELINE_LABEL, GTK_STATE_NORMAL, &COLOR_GREEN);
887      gtk_widget_modify_bg(modeline_bg, GTK_STATE_NORMAL, &COLOR_BLACK);
888    
889      gtk_box_pack_start(GTK_BOX(vbox), modeline_bg, TRUE, TRUE, 0);
890    
891      /* C-x C-s などの状態を表示するステータスバーをウィンドウボトムに追加 */
892      Shiki_EDITOR_STATUSBAR = gtk_statusbar_new();
893      gtk_box_pack_start(GTK_BOX(vbox), Shiki_EDITOR_STATUSBAR, TRUE, TRUE, 0);
894      contextid = gtk_statusbar_get_context_id(GTK_STATUSBAR(Shiki_EDITOR_STATUSBAR), "");
895    
896      /* キーバインドのハンドリングを登録 */
897      g_signal_connect(G_OBJECT(Shiki_EDITOR_NOTEBOOK), "key-press-event", G_CALLBACK (signal_key_press_handler), GINT_TO_POINTER(contextid));
898      g_signal_connect(G_OBJECT(Shiki_EDITOR_NOTEBOOK), "key-release-event", G_CALLBACK (signal_key_release_handler), GINT_TO_POINTER(contextid));
899    
900      /* 引数に指定されたファイルを開く */
901      if(argc >= 2) {
902        int i;
903        for(i = 1; i < argc; i++)
904          Shiki_create_file_buffer(argv[i]);
905      } else /* 指定されてなければ,デフォルトのページを追加 */
906        open_online_help(Shiki_EDITOR_NOTEBOOK);
907    
908      gtk_widget_grab_focus(GTK_WIDGET(Shiki_EDITOR_NOTEBOOK));
909      gtk_widget_show_all(Shiki_EDITOR_WINDOW);
910    }
911    
912    ScmClass *ShikiBufferClass = NULL;
913    
914    static void buffer_print(ScmObj obj, ScmPort *out, ScmWriteContext *ctx) {
915      GtkTextBuffer *b = SHIKI_BUFFER_UNBOX(obj);
916      GList *l  = g_list_find_custom(Shiki_EDITOR_BUFFER_LIST, b, compBuffer);
917      if(l)
918        Scm_Printf(out, "#<buffer: %s>", ((ShikiBuffer *)(l->data))->name);
919      else
920        Scm_Printf(out, "#<deleted buffer: %p>", b);
921    }
922    
923    gtk_widget_show_all(editor_window);  static void buffer_cleanup(ScmObj obj)
924    {
925      g_object_unref(SHIKI_BUFFER_UNBOX(obj));
926  }  }
927    
928  int main(int argc, char *argv[]) {  int main(int argc, char *argv[]) {
929    /* 初期化してメインループへ */    /* 初期化してメインループへ */
930    gtk_set_locale();    Shiki_EDITOR_DEFAULT_LOCALE = g_locale_to_utf8(gtk_set_locale(), -1, NULL, NULL, NULL);
931    gtk_init(&argc, &argv);    gtk_init(&argc, &argv);
932    GC_INIT(); Scm_Init(GAUCHE_SIGNATURE);    GC_INIT(); Scm_Init(GAUCHE_SIGNATURE);
933    editor_window_init();    Scm_Load("gauche-init.scm", 0);
934      ShikiBufferClass = Scm_MakeForeignPointerClass(SCM_CURRENT_MODULE(),
935          "<buffer>", buffer_print, buffer_cleanup,
936          SCM_FOREIGN_POINTER_KEEP_IDENTITY
937          |
938          SCM_FOREIGN_POINTER_MAP_NULL);
939      /* バッファ名を一意にするためのハッシュテーブル */
940      Shiki_EDITOR_BUFNAME_HASH = g_hash_table_new (g_str_hash, g_str_equal);
941      Shiki_editor_window_init(argc, argv);
942    gtk_main();    gtk_main();
943    Scm_Exit(0);    Scm_Exit(0);
944    return 0;    return 0;

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.67

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26