| 30 |
#include<gdk/gdkkeysyms.h> |
#include<gdk/gdkkeysyms.h> |
| 31 |
|
|
| 32 |
static gint editor_indent_width = 2; |
static gint editor_indent_width = 2; |
| 33 |
|
|
| 34 |
static GtkWidget *editor_window; |
static GtkWidget *editor_window; |
| 35 |
|
static GtkScrolledWindow *current_tabpage; |
| 36 |
|
static gint current_tabpage_num; |
| 37 |
|
static const gchar *current_tabpage_label; |
| 38 |
|
static GtkTextView *current_text_view; |
| 39 |
|
static GtkTextBuffer *current_text_buffer; |
| 40 |
|
|
| 41 |
|
|
| 42 |
/* テキストバッファから全ての文字列を取り出す */ |
/* テキストバッファから全ての文字列を取り出す */ |
| 43 |
static gchar* get_all_buffer_contents(GtkTextBuffer *buffer) { |
static gchar* get_all_buffer_contents(GtkTextBuffer *buffer) { |
| 77 |
gtk_widget_destroy(dialog); |
gtk_widget_destroy(dialog); |
| 78 |
return filename; |
return filename; |
| 79 |
} |
} |
|
/* 現在表示されているページのテキストビューワを取り出す */ |
|
|
static GtkTextView* get_text_view_from_current_tabpage(GtkNotebook* notebook) { |
|
|
gint pagenum = gtk_notebook_get_current_page(notebook); |
|
|
GtkScrolledWindow *scrolledwindow = GTK_SCROLLED_WINDOW(gtk_notebook_get_nth_page(notebook, pagenum)); |
|
|
/* GtkBin は一つしか子を持たない抽象コンテナクラス */ |
|
|
return GTK_TEXT_VIEW(gtk_bin_get_child(GTK_BIN(scrolledwindow))); |
|
|
} |
|
|
|
|
|
|
|
|
/* 現在表示されているページのテキストバッファを取り出す */ |
|
|
static GtkTextBuffer* get_text_buffer_from_current_tabpage(GtkNotebook* notebook) { |
|
|
return gtk_text_view_get_buffer(get_text_view_from_current_tabpage(notebook)); |
|
|
} |
|
|
|
|
|
/* 現在表示されているタブが開いているファイルの名前を返す */ |
|
| 80 |
|
|
| 81 |
/* 現在表示されているページの内容をファイルに保存 */ |
/* 現在表示されているページの内容をファイルに保存 */ |
| 82 |
static void save_file_from_notebook(GtkNotebook *notebook) { |
static void save_file_from_notebook(GtkNotebook *notebook) { |
|
GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(notebook); |
|
|
gchar *filename; |
|
|
gint current_page; |
|
| 83 |
|
|
| 84 |
/* 変更が無ければ何もしない */ |
/* 変更が無ければ何もしない */ |
| 85 |
if(!gtk_text_buffer_get_modified(buffer)) return; |
if(!gtk_text_buffer_get_modified(current_text_buffer)) return; |
|
|
|
|
/* 現在表示されているタブが開いているファイルの名前を取得 */ |
|
|
current_page = gtk_notebook_get_current_page(notebook); |
|
|
filename = g_strdup(gtk_notebook_get_tab_label_text(notebook, gtk_notebook_get_nth_page(notebook, current_page))); |
|
| 86 |
|
|
| 87 |
/* まだファイル名が設定されていなかったら,ダイアログを開いて入力させる */ |
/* まだファイル名が設定されていなかったら,ダイアログを開いて入力させる */ |
| 88 |
if(!filename || g_ascii_strcasecmp("*scratch*", filename) == 0) { |
if(g_ascii_strcasecmp("*scratch*", current_tabpage_label) == 0) { |
| 89 |
|
gchar *filename = get_filename_from_dialog("Save File As ..."); |
| 90 |
|
if(!filename) return; |
| 91 |
|
if(!save_text_buffer(filename, current_text_buffer)) return; |
| 92 |
|
gtk_notebook_set_tab_label_text(notebook, GTK_WIDGET(current_tabpage), filename); |
| 93 |
|
gtk_window_set_title (GTK_WINDOW(editor_window), filename); |
| 94 |
g_free(filename); |
g_free(filename); |
|
if(!save_text_buffer(filename = get_filename_from_dialog("Save File As ..."), buffer)) |
|
|
return; |
|
| 95 |
} else |
} else |
| 96 |
save_text_buffer(filename, buffer); |
save_text_buffer(current_tabpage_label, current_text_buffer); |
|
|
|
|
gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook), |
|
|
gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), current_page), |
|
|
filename); |
|
|
gtk_window_set_title (GTK_WINDOW (editor_window), filename); |
|
|
g_free(filename); |
|
| 97 |
} |
} |
| 98 |
|
|
| 99 |
/* ファイルを保存するイベントハンドラ */ |
/* ファイルを保存するイベントハンドラ */ |
| 103 |
|
|
| 104 |
/* 現在表示されているページの内容をファイルに別名保存 */ |
/* 現在表示されているページの内容をファイルに別名保存 */ |
| 105 |
static void save_file_as_from_notebook(GtkNotebook *notebook) { |
static void save_file_as_from_notebook(GtkNotebook *notebook) { |
|
gint current_page; |
|
|
GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(notebook); |
|
| 106 |
gchar *filename = get_filename_from_dialog("Save File As ..."); |
gchar *filename = get_filename_from_dialog("Save File As ..."); |
| 107 |
|
|
| 108 |
if(!save_text_buffer(filename, buffer)) return; |
if(!filename) return; |
| 109 |
|
if(!save_text_buffer(filename, current_text_buffer)) return; |
|
current_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)); |
|
|
gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook), |
|
|
gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), current_page), |
|
|
filename); |
|
| 110 |
|
|
| 111 |
|
gtk_notebook_set_tab_label_text(notebook, GTK_WIDGET(current_tabpage), filename); |
| 112 |
gtk_window_set_title (GTK_WINDOW (editor_window), filename); |
gtk_window_set_title (GTK_WINDOW (editor_window), filename); |
| 113 |
|
|
| 114 |
g_free(filename); |
g_free(filename); |
| 200 |
gchar *contents, *text; |
gchar *contents, *text; |
| 201 |
gsize br, bw, len; |
gsize br, bw, len; |
| 202 |
GError *err = NULL; |
GError *err = NULL; |
|
|
|
| 203 |
gchar *filename = get_filename_from_dialog("File Selection"); |
gchar *filename = get_filename_from_dialog("File Selection"); |
| 204 |
|
|
| 205 |
if(!filename) return; |
if(!filename) return; |
| 269 |
|
|
| 270 |
/* 緑ボタンのハンドリング.バッファの選択されている S 式を評価 */ |
/* 緑ボタンのハンドリング.バッファの選択されている S 式を評価 */ |
| 271 |
static void buffer_exec_handler(GtkWidget *widget, GtkWidget *notebook) { |
static void buffer_exec_handler(GtkWidget *widget, GtkWidget *notebook) { |
|
GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook)); |
|
| 272 |
|
|
| 273 |
GtkTextIter start, end, p; |
GtkTextIter start, end, p; |
| 274 |
gchar *code; |
gchar *code; |
| 275 |
gtk_text_buffer_get_end_iter(buffer, &p); |
gtk_text_buffer_get_end_iter(current_text_buffer, &p); |
| 276 |
gtk_text_buffer_insert(buffer, &p, "\n\n", -1); |
gtk_text_buffer_insert(current_text_buffer, &p, "\n\n", -1); |
| 277 |
|
|
| 278 |
/* マウスで選択されている範囲の文字列を取得 */ |
/* マウスで選択されている範囲の文字列を取得 */ |
| 279 |
if(gtk_text_buffer_get_selection_bounds(buffer, &start, &end)) { |
if(gtk_text_buffer_get_selection_bounds(current_text_buffer, &start, &end)) { |
| 280 |
code = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); |
code = gtk_text_buffer_get_text(current_text_buffer, &start, &end, FALSE); |
| 281 |
gtk_text_buffer_insert(buffer, &p, eval_cstring_by_gauche(code), -1); |
gtk_text_buffer_insert(current_text_buffer, &p, eval_cstring_by_gauche(code), -1); |
| 282 |
g_free(code); |
g_free(code); |
| 283 |
} |
} |
|
|
|
| 284 |
} |
} |
| 285 |
|
|
| 286 |
// GtkTextCharPredicate |
// GtkTextCharPredicate |
| 334 |
|
|
| 335 |
/* タブが切り替わる時のイベントハンドリング */ |
/* タブが切り替わる時のイベントハンドリング */ |
| 336 |
static void switch_page(GtkNotebook *notebook, GtkNotebookPage *page, guint pagenum, gpointer p) { |
static void switch_page(GtkNotebook *notebook, GtkNotebookPage *page, guint pagenum, gpointer p) { |
| 337 |
|
|
| 338 |
|
/* 現在のタブ,ビューワ,バッファを切替える */ |
| 339 |
|
current_tabpage = GTK_SCROLLED_WINDOW(gtk_notebook_get_nth_page(notebook, pagenum)); |
| 340 |
|
current_tabpage_num = pagenum; |
| 341 |
|
/* GtkBin は一つしか子を持たない抽象コンテナクラス */ |
| 342 |
|
current_text_view = GTK_TEXT_VIEW(gtk_bin_get_child(GTK_BIN(current_tabpage))); |
| 343 |
|
current_text_buffer = gtk_text_view_get_buffer(current_text_view); |
| 344 |
|
|
| 345 |
/* タブのラベルをウィンドウのタイトルに */ |
/* タブのラベルをウィンドウのタイトルに */ |
| 346 |
gtk_window_set_title (GTK_WINDOW(editor_window), gtk_notebook_get_tab_label_text(notebook, GTK_WIDGET(gtk_notebook_get_nth_page(notebook, pagenum)))); |
gtk_window_set_title (GTK_WINDOW(editor_window), current_tabpage_label = gtk_notebook_get_tab_label_text(notebook, GTK_WIDGET(current_tabpage))); |
| 347 |
} |
} |
| 348 |
|
|
| 349 |
/* ページのタブと境界線を on/off */ |
/* ページのタブと境界線を on/off */ |
| 361 |
|
|
| 362 |
/* ノートブックからページを削除 */ |
/* ノートブックからページを削除 */ |
| 363 |
static void remove_tabpage(GtkNotebook *notebook) { |
static void remove_tabpage(GtkNotebook *notebook) { |
| 364 |
GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(notebook); |
if(!not_yet_save_changes_really_quit(current_text_buffer)) { |
| 365 |
if(!not_yet_save_changes_really_quit(buffer)) { |
gtk_notebook_remove_page(notebook, current_tabpage_num); |
|
gint page = gtk_notebook_get_current_page(notebook); |
|
|
gtk_notebook_remove_page(notebook, page); |
|
| 366 |
/* ウィジットを強制的に再描画 */ |
/* ウィジットを強制的に再描画 */ |
| 367 |
gtk_widget_queue_draw(GTK_WIDGET(notebook)); |
gtk_widget_queue_draw(GTK_WIDGET(notebook)); |
| 368 |
} |
} |
| 386 |
/* 特定のキー操作のハンドリング */ |
/* 特定のキー操作のハンドリング */ |
| 387 |
|
|
| 388 |
/* カーソルの移動 ^npfb */ |
/* カーソルの移動 ^npfb */ |
| 389 |
static void forward_buffer_from_current_tabpage(GtkNotebook *notebook) { |
static void forward_current_buffer() { |
|
GtkTextBuffer *b = get_text_buffer_from_current_tabpage(notebook); |
|
| 390 |
GtkTextIter p; |
GtkTextIter p; |
| 391 |
gtk_text_buffer_get_iter_at_mark(b,&p, gtk_text_buffer_get_insert(b)); |
gtk_text_buffer_get_iter_at_mark(current_text_buffer,&p, gtk_text_buffer_get_insert(current_text_buffer)); |
| 392 |
gtk_text_iter_forward_char(&p); |
gtk_text_iter_forward_char(&p); |
| 393 |
gtk_text_buffer_place_cursor(b, &p); |
gtk_text_buffer_place_cursor(current_text_buffer, &p); |
| 394 |
} |
} |
| 395 |
static void backward_buffer_from_current_tabpage(GtkNotebook *notebook) { |
static void backward_current_buffer() { |
|
GtkTextBuffer *b = get_text_buffer_from_current_tabpage(notebook); |
|
| 396 |
GtkTextIter p; |
GtkTextIter p; |
| 397 |
gtk_text_buffer_get_iter_at_mark(b,&p, gtk_text_buffer_get_insert(b)); |
gtk_text_buffer_get_iter_at_mark(current_text_buffer,&p, gtk_text_buffer_get_insert(current_text_buffer)); |
| 398 |
gtk_text_iter_backward_char(&p); |
gtk_text_iter_backward_char(&p); |
| 399 |
gtk_text_buffer_place_cursor(b, &p); |
gtk_text_buffer_place_cursor(current_text_buffer, &p); |
| 400 |
} |
} |
| 401 |
static void line_forward_buffer_from_current_tabpage(GtkNotebook *notebook) { |
static void line_forward_current_buffer() { |
|
GtkTextView *v = get_text_view_from_current_tabpage(notebook); |
|
|
GtkTextBuffer *b = gtk_text_view_get_buffer(v); |
|
| 402 |
GtkTextIter p; |
GtkTextIter p; |
| 403 |
gtk_text_buffer_get_iter_at_mark(b,&p, gtk_text_buffer_get_insert(b)); |
gtk_text_buffer_get_iter_at_mark(current_text_buffer, &p, gtk_text_buffer_get_insert(current_text_buffer)); |
| 404 |
gtk_text_view_forward_display_line(v, &p); |
gtk_text_view_forward_display_line(current_text_view, &p); |
| 405 |
gtk_text_buffer_place_cursor(b, &p); |
gtk_text_buffer_place_cursor(current_text_buffer, &p); |
| 406 |
} |
} |
| 407 |
static void line_backward_buffer_from_current_tabpage(GtkNotebook *notebook) { |
static void line_backward_current_buffer() { |
|
GtkTextView *v = get_text_view_from_current_tabpage(notebook); |
|
|
GtkTextBuffer *b = gtk_text_view_get_buffer(v); |
|
| 408 |
GtkTextIter p; |
GtkTextIter p; |
| 409 |
gtk_text_buffer_get_iter_at_mark(b,&p, gtk_text_buffer_get_insert(b)); |
gtk_text_buffer_get_iter_at_mark(current_text_buffer,&p, gtk_text_buffer_get_insert(current_text_buffer)); |
| 410 |
gtk_text_view_backward_display_line(v, &p); |
gtk_text_view_backward_display_line(current_text_view, &p); |
| 411 |
gtk_text_buffer_place_cursor(b, &p); |
gtk_text_buffer_place_cursor(current_text_buffer, &p); |
| 412 |
} |
} |
| 413 |
|
|
| 414 |
/* キーが押された */ |
/* キーが押された */ |
| 415 |
static gboolean signal_key_press_handler (GtkWidget *notebook, GdkEventKey *event, gpointer p) { |
static gboolean signal_key_press_handler (GtkWidget *notebook, GdkEventKey *event, gpointer p) { |
|
GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook)); |
|
| 416 |
GtkTextIter start, end; |
GtkTextIter start, end; |
| 417 |
|
|
| 418 |
/* 括弧の対応の強調を無効に */ |
/* 括弧の対応の強調を無効に */ |
| 419 |
gtk_text_buffer_get_start_iter(buffer, &start); |
gtk_text_buffer_get_start_iter(current_text_buffer, &start); |
| 420 |
gtk_text_buffer_get_end_iter(buffer, &end); |
gtk_text_buffer_get_end_iter(current_text_buffer, &end); |
| 421 |
gtk_text_buffer_remove_tag_by_name(buffer, "parent_emphasis_background", &start, &end); |
gtk_text_buffer_remove_tag_by_name(current_text_buffer, "parent_emphasis_background", &start, &end); |
| 422 |
|
|
| 423 |
if(event->state & GDK_CONTROL_MASK) { |
if(event->state & GDK_CONTROL_MASK) { |
| 424 |
switch(event->keyval) { |
switch(event->keyval) { |
| 425 |
case GDK_f : /* Ctrl + f : forward */ |
case GDK_f : /* Ctrl + f : forward */ |
| 426 |
forward_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook)); |
forward_current_buffer(); |
| 427 |
break; |
break; |
| 428 |
case GDK_b : /* Ctrl + b : backward */ |
case GDK_b : /* Ctrl + b : backward */ |
| 429 |
backward_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook)); |
backward_current_buffer(); |
| 430 |
break; |
break; |
| 431 |
case GDK_n : /* Ctrl + n : next line */ |
case GDK_n : /* Ctrl + n : next line */ |
| 432 |
line_forward_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook)); |
line_forward_current_buffer(); |
| 433 |
break; |
break; |
| 434 |
case GDK_p : /* Ctrl + p : previous line */ |
case GDK_p : /* Ctrl + p : previous line */ |
| 435 |
line_backward_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook)); |
line_backward_current_buffer(); |
| 436 |
break; |
break; |
| 437 |
|
|
| 438 |
case GDK_j : /* Ctrl + j : カーソル手前の S 式の評価 */ |
case GDK_j : /* Ctrl + j : カーソル手前の S 式の評価 */ |
| 441 |
GtkTextIter start, end; |
GtkTextIter start, end; |
| 442 |
|
|
| 443 |
/* カーソルの位置を取得 */ |
/* カーソルの位置を取得 */ |
| 444 |
gtk_text_buffer_get_iter_at_mark(buffer, &end, gtk_text_buffer_get_insert(buffer)); |
gtk_text_buffer_get_iter_at_mark(current_text_buffer, &end, gtk_text_buffer_get_insert(current_text_buffer)); |
| 445 |
|
|
| 446 |
gtk_text_iter_backward_find_char(&end, is_kokka, NULL, NULL); |
gtk_text_iter_backward_find_char(&end, is_kokka, NULL, NULL); |
| 447 |
start = end; |
start = end; |
| 450 |
/* カーソル位置の前にある S 式を切り出す */ |
/* カーソル位置の前にある S 式を切り出す */ |
| 451 |
if(!search_sexp_string(&start)) return FALSE; |
if(!search_sexp_string(&start)) return FALSE; |
| 452 |
|
|
| 453 |
code = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); |
code = gtk_text_buffer_get_text(current_text_buffer, &start, &end, FALSE); |
| 454 |
gtk_text_buffer_insert(buffer, &end, "\n\n", -1); |
gtk_text_buffer_insert(current_text_buffer, &end, "\n\n", -1); |
| 455 |
gtk_text_buffer_insert(buffer, &end, eval_cstring_by_gauche(code), -1); |
gtk_text_buffer_insert(current_text_buffer, &end, eval_cstring_by_gauche(code), -1); |
| 456 |
g_free(code); |
g_free(code); |
| 457 |
} |
} |
| 458 |
break; |
break; |
| 472 |
|
|
| 473 |
/* キーが離された */ |
/* キーが離された */ |
| 474 |
static gboolean signal_key_release_handler (GtkWidget *notebook, GdkEventKey *event, gpointer p) { |
static gboolean signal_key_release_handler (GtkWidget *notebook, GdkEventKey *event, gpointer p) { |
|
|
|
|
GtkTextBuffer *buffer = get_text_buffer_from_current_tabpage(GTK_NOTEBOOK(notebook)); |
|
| 475 |
//static gint metakey_pressed = 0; |
//static gint metakey_pressed = 0; |
| 476 |
static gint controlx_pressed = 0; |
static gint controlx_pressed = 0; |
| 477 |
|
|
| 479 |
GtkTextIter start, end; |
GtkTextIter start, end; |
| 480 |
|
|
| 481 |
/* カーソルの位置を取得 */ |
/* カーソルの位置を取得 */ |
| 482 |
gtk_text_buffer_get_iter_at_mark(buffer, &end, gtk_text_buffer_get_insert(buffer)); |
gtk_text_buffer_get_iter_at_mark(current_text_buffer, &end, gtk_text_buffer_get_insert(current_text_buffer)); |
| 483 |
|
|
| 484 |
start = end; |
start = end; |
| 485 |
gtk_text_iter_backward_char(&start); |
gtk_text_iter_backward_char(&start); |
| 487 |
/* カーソル位置の前にある S 式を切り出す */ |
/* カーソル位置の前にある S 式を切り出す */ |
| 488 |
if(!search_sexp_string(&start)) return FALSE; |
if(!search_sexp_string(&start)) return FALSE; |
| 489 |
|
|
| 490 |
gtk_text_buffer_apply_tag_by_name(buffer, "parent_emphasis_background", &start, &end); |
gtk_text_buffer_apply_tag_by_name(current_text_buffer, "parent_emphasis_background", &start, &end); |
| 491 |
} |
} |
| 492 |
|
|
| 493 |
/* 改行されるたびに,自動的に括弧のネストの深さに応じた数のスペース (インデント) が行頭に入る */ |
/* 改行されるたびに,自動的に括弧のネストの深さに応じた数のスペース (インデント) が行頭に入る */ |
| 494 |
if(event->keyval == GDK_Return) { |
if(event->keyval == GDK_Return) { |
| 495 |
gint indentWidth = get_parent_nest_level_at_cursor(buffer) * editor_indent_width; |
gint indentWidth = get_parent_nest_level_at_cursor(current_text_buffer) * editor_indent_width; |
| 496 |
gchar *indent = g_strnfill(indentWidth, ' '); |
gchar *indent = g_strnfill(indentWidth, ' '); |
| 497 |
gtk_text_buffer_insert_at_cursor(buffer, indent, -1); |
gtk_text_buffer_insert_at_cursor(current_text_buffer, indent, -1); |
| 498 |
g_free(indent); |
g_free(indent); |
| 499 |
} |
} |
| 500 |
|
|