| 54 |
|
|
| 55 |
/* タブの生成と削除 : 基本的に,ShikiBuffer の中身に格納する情報を増やしたかったら,この 2 つの関数だけを変更すれば良い (ようにする…) */ |
/* タブの生成と削除 : 基本的に,ShikiBuffer の中身に格納する情報を増やしたかったら,この 2 つの関数だけを変更すれば良い (ようにする…) */ |
| 56 |
extern void Scm_Init_xyzzylisp(ScmModule *module); |
extern void Scm_Init_xyzzylisp(ScmModule *module); |
|
static void get_buffer_create(gchar *filename); |
|
| 57 |
static void remove_tabpage(); |
static void remove_tabpage(); |
| 58 |
|
|
| 59 |
/* foo_bar_handler() は,イベントハンドラのためのラッパー */ |
/* foo_bar_handler() は,イベントハンドラのためのラッパー */ |
| 60 |
static void append_default_tabpage_handler(); |
static void append_default_tabpage_handler(); |
| 61 |
|
|
| 62 |
/* ファイル関係 */ |
/* ファイル関係 */ |
| 63 |
static void open_file(gchar *filename); |
static void open_file(const gchar *filename); |
| 64 |
static void open_file_handler(); |
static void open_file_handler(); |
| 65 |
static void save_file(); |
static void save_file(); |
| 66 |
static void save_file_as(); |
static void save_file_as(); |
|
static gchar *get_filename_from_dialog(const gchar *msg); |
|
| 67 |
|
|
| 68 |
/* テキストバッファ関係 */ |
/* テキストバッファ関係 */ |
| 69 |
static gchar* get_all_buffer_contents(GtkTextBuffer *buffer); |
static gchar* get_all_buffer_contents(GtkTextBuffer *buffer); |
| 70 |
static gboolean save_text_buffer(const gchar *filename, GtkTextBuffer *buffer); |
static gboolean save_text_buffer(const gchar *filename, GtkTextBuffer *buffer); |
| 71 |
static void clear_current_buffer(); |
static void clear_current_buffer_handler(); |
| 72 |
static void undo(); |
static void undo(); |
| 73 |
static void search_current_buffer(); |
static void search_current_buffer(); |
| 74 |
static void insert_text_handler(GtkTextBuffer *buffer, GtkTextIter *p, gchar *str, gint len); |
static void insert_text_handler(GtkTextBuffer *buffer, GtkTextIter *p, gchar *str, gint len); |
| 108 |
static void tabsborder_on_off(GtkButton *button, GtkNotebook *notebook); |
static void tabsborder_on_off(GtkButton *button, GtkNotebook *notebook); |
| 109 |
static void rotate_tab_position(GtkButton *button, GtkNotebook *notebook); |
static void rotate_tab_position(GtkButton *button, GtkNotebook *notebook); |
| 110 |
|
|
|
/* バッファ内 ↑↓←→ 移動 */ |
|
|
static void forward_current_buffer(); |
|
|
static void backward_current_buffer(); |
|
|
static void line_forward_current_buffer(); |
|
|
static void line_backward_current_buffer(); |
|
|
|
|
| 111 |
/* キーバインド全般 */ |
/* キーバインド全般 */ |
| 112 |
static gboolean signal_key_press_handler(GtkWidget *notebook, GdkEventKey *event, gpointer contextid); |
static gboolean signal_key_press_handler(GtkWidget *notebook, GdkEventKey *event, gpointer contextid); |
| 113 |
static gboolean signal_key_release_handler(GtkWidget *notebook, GdkEventKey *event, gpointer contextid); |
static gboolean signal_key_release_handler(GtkWidget *notebook, GdkEventKey *event, gpointer contextid); |
| 120 |
static void Shiki_editor_window_init(int argc, char **argv); |
static void Shiki_editor_window_init(int argc, char **argv); |
| 121 |
|
|
| 122 |
/* バッファの内容を消去 */ |
/* バッファの内容を消去 */ |
| 123 |
static void clear_current_buffer() { |
static void clear_current_buffer_handler() { |
| 124 |
GtkTextIter start, end; |
Shiki_erase_buffer(Shiki_CURRENT_TEXT_BUFFER); |
|
gtk_text_buffer_get_start_iter(Shiki_CURRENT_TEXT_BUFFER, &start); |
|
|
gtk_text_buffer_get_end_iter(Shiki_CURRENT_TEXT_BUFFER, &end); |
|
|
gtk_text_buffer_delete(Shiki_CURRENT_TEXT_BUFFER, &start, &end); |
|
| 125 |
} |
} |
| 126 |
|
|
| 127 |
static void destroy_handler(GtkWidget *button, GtkWidget *widget) {gtk_widget_destroy(widget);} |
static void destroy_handler(GtkWidget *button, GtkWidget *widget) {gtk_widget_destroy(widget);} |
| 388 |
} else if(event->state & GDK_CONTROL_MASK) { |
} else if(event->state & GDK_CONTROL_MASK) { |
| 389 |
switch(event->keyval) { |
switch(event->keyval) { |
| 390 |
case GDK_f : /* Ctrl + f : forward */ |
case GDK_f : /* Ctrl + f : forward */ |
| 391 |
forward_current_buffer(); |
Shiki_forward_char(); |
| 392 |
break; |
break; |
| 393 |
case GDK_b : /* Ctrl + b : backward */ |
case GDK_b : /* Ctrl + b : backward */ |
| 394 |
backward_current_buffer(); |
Shiki_backward_char(); |
| 395 |
break; |
break; |
| 396 |
case GDK_n : /* Ctrl + n : next line */ |
case GDK_n : /* Ctrl + n : next line */ |
| 397 |
line_forward_current_buffer(); |
Shiki_forward_line(1); |
| 398 |
break; |
break; |
| 399 |
case GDK_p : /* Ctrl + p : previous line */ |
case GDK_p : /* Ctrl + p : previous line */ |
| 400 |
line_backward_current_buffer(); |
Shiki_forward_line(-1); |
| 401 |
break; |
break; |
| 402 |
case GDK_h : |
case GDK_h : |
| 403 |
{ GtkTextIter p; |
{ GtkTextIter p; |
| 492 |
} |
} |
| 493 |
|
|
| 494 |
/* ノートブックにタブとページ (バッファ) を追加 */ |
/* ノートブックにタブとページ (バッファ) を追加 */ |
| 495 |
static void get_buffer_create(gchar *filename) { |
GtkTextBuffer *Shiki_new_buffer_create(gchar *filename) { |
| 496 |
/*-------------------- 新しいタブを作る ----------------------------------*/ |
/*-------------------- 新しいタブを作る ----------------------------------*/ |
| 497 |
/* ShikiBuffer には,タブに関連する情報が全て保持されている */ |
/* ShikiBuffer には,タブに関連する情報が全て保持されている */ |
| 498 |
ShikiBuffer *tabinfo = g_malloc(sizeof(ShikiBuffer)); |
ShikiBuffer *tabinfo = g_malloc(sizeof(ShikiBuffer)); |
| 512 |
/* xyzzy lisp 関数を登録 */ |
/* xyzzy lisp 関数を登録 */ |
| 513 |
Scm_Init_xyzzylisp(SCM_MODULE(tabinfo->env)); |
Scm_Init_xyzzylisp(SCM_MODULE(tabinfo->env)); |
| 514 |
|
|
|
g_return_if_fail(tabinfo->env != SCM_FALSE); |
|
|
|
|
| 515 |
/* スクロールウィンドウ (タブの中身の大外) を作る */ |
/* スクロールウィンドウ (タブの中身の大外) を作る */ |
| 516 |
tabinfo->tabpage = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); |
tabinfo->tabpage = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); |
| 517 |
gtk_scrolled_window_set_policy (tabinfo->tabpage, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
gtk_scrolled_window_set_policy (tabinfo->tabpage, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
| 551 |
gtk_widget_show_all(GTK_WIDGET(Shiki_EDITOR_NOTEBOOK)); |
gtk_widget_show_all(GTK_WIDGET(Shiki_EDITOR_NOTEBOOK)); |
| 552 |
/* 開いたページに移動する */ |
/* 開いたページに移動する */ |
| 553 |
gtk_notebook_set_current_page(Shiki_EDITOR_NOTEBOOK, g_list_length(Shiki_EDITOR_BUFFER_LIST) - 1); |
gtk_notebook_set_current_page(Shiki_EDITOR_NOTEBOOK, g_list_length(Shiki_EDITOR_BUFFER_LIST) - 1); |
| 554 |
|
|
| 555 |
|
return tabinfo->text_buffer; |
| 556 |
} |
} |
| 557 |
|
|
| 558 |
static void append_default_tabpage_handler() { |
static void append_default_tabpage_handler() { |
| 559 |
get_buffer_create(g_strdup("*scratch*")); |
Shiki_new_buffer_create(g_strdup("*scratch*")); |
| 560 |
} |
} |
| 561 |
|
|
| 562 |
/* ノートブックからタブとページ (バッファ) を削除 */ |
/* ノートブックからタブとページ (バッファ) を削除 */ |
| 597 |
gchar *contents, *text; |
gchar *contents, *text; |
| 598 |
gsize br, bw, len; |
gsize br, bw, len; |
| 599 |
GError *err = NULL; |
GError *err = NULL; |
| 600 |
gchar *filename = get_filename_from_dialog("File Selection"); |
const gchar *filename = Shiki_file_name_dialog("File Selection"); |
| 601 |
GtkTextIter p; |
GtkTextIter p; |
| 602 |
|
|
| 603 |
if(!filename) return; |
if(!filename) return; |
| 611 |
else |
else |
| 612 |
gtk_text_buffer_insert(Shiki_CURRENT_TEXT_BUFFER, &p, load_cstring_by_gauche(contents), -1); |
gtk_text_buffer_insert(Shiki_CURRENT_TEXT_BUFFER, &p, load_cstring_by_gauche(contents), -1); |
| 613 |
} |
} |
| 614 |
g_free(text); g_free(contents); g_free(filename); |
g_free(text); g_free(contents); |
| 615 |
} |
} |
| 616 |
|
|
| 617 |
/* gauche を起動して文字列をロード */ |
/* gauche を起動して文字列をロード */ |
| 735 |
return TRUE; |
return TRUE; |
| 736 |
} |
} |
| 737 |
|
|
|
/* ダイアログを開き,ファイル名を取得.msg はダイアログのメッセージ */ |
|
|
static gchar *get_filename_from_dialog(const gchar *msg) { |
|
|
|
|
|
GtkWidget *dialog = gtk_file_selection_new(msg); |
|
|
gint resp = gtk_dialog_run(GTK_DIALOG(dialog)); |
|
|
gchar *filename = NULL; |
|
|
|
|
|
/* gtk_file_selection_get_filename が返す文字列定数は静的に確保されたバッファを指しているので,コピーしなければならない */ |
|
|
if(resp == GTK_RESPONSE_OK) |
|
|
filename = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(dialog))); |
|
|
|
|
|
gtk_widget_destroy(dialog); |
|
|
return filename; |
|
|
} |
|
|
|
|
| 738 |
/* 現在表示されているページの内容をファイルに保存 */ |
/* 現在表示されているページの内容をファイルに保存 */ |
| 739 |
static void save_file() { |
static void save_file() { |
| 740 |
|
|
| 746 |
|
|
| 747 |
/* まだファイル名が設定されていなかったら,ダイアログを開いて入力させる */ |
/* まだファイル名が設定されていなかったら,ダイアログを開いて入力させる */ |
| 748 |
if(g_ascii_strcasecmp("*scratch*", Shiki_CURRENT_TAB_TITLE) == 0) { |
if(g_ascii_strcasecmp("*scratch*", Shiki_CURRENT_TAB_TITLE) == 0) { |
| 749 |
gchar *filename = get_filename_from_dialog("Save File As ..."); |
const gchar *filename = Shiki_file_name_dialog("Save File As ..."); |
| 750 |
if(!filename) return; |
if(!filename) return; |
| 751 |
if(!save_text_buffer(filename, Shiki_CURRENT_TEXT_BUFFER)) return; |
if(!save_text_buffer(filename, Shiki_CURRENT_TEXT_BUFFER)) return; |
| 752 |
gtk_notebook_set_tab_label_text(Shiki_EDITOR_NOTEBOOK, GTK_WIDGET(Shiki_CURRENT_TAB), filename); |
gtk_notebook_set_tab_label_text(Shiki_EDITOR_NOTEBOOK, GTK_WIDGET(Shiki_CURRENT_TAB), filename); |
| 753 |
gtk_window_set_title (GTK_WINDOW(Shiki_EDITOR_WINDOW), filename); |
gtk_window_set_title (GTK_WINDOW(Shiki_EDITOR_WINDOW), filename); |
|
g_free(filename); |
|
| 754 |
} else |
} else |
| 755 |
save_text_buffer(Shiki_CURRENT_TAB_TITLE, Shiki_CURRENT_TEXT_BUFFER); |
save_text_buffer(Shiki_CURRENT_TAB_TITLE, Shiki_CURRENT_TEXT_BUFFER); |
| 756 |
} |
} |
| 757 |
|
|
| 758 |
/* 現在表示されているページの内容をファイルに別名保存 */ |
/* 現在表示されているページの内容をファイルに別名保存 */ |
| 759 |
static void save_file_as() { |
static void save_file_as() { |
| 760 |
gchar *filename = get_filename_from_dialog("Save File As ..."); |
const gchar *filename = Shiki_file_name_dialog("Save File As ..."); |
| 761 |
|
|
| 762 |
if(!filename) return; |
if(!filename) return; |
| 763 |
if(!save_text_buffer(filename, Shiki_CURRENT_TEXT_BUFFER)) return; |
if(!save_text_buffer(filename, Shiki_CURRENT_TEXT_BUFFER)) return; |
| 764 |
|
|
| 765 |
gtk_notebook_set_tab_label_text(Shiki_EDITOR_NOTEBOOK, GTK_WIDGET(Shiki_CURRENT_TAB), filename); |
gtk_notebook_set_tab_label_text(Shiki_EDITOR_NOTEBOOK, GTK_WIDGET(Shiki_CURRENT_TAB), filename); |
| 766 |
gtk_window_set_title (GTK_WINDOW (Shiki_EDITOR_WINDOW), filename); |
gtk_window_set_title (GTK_WINDOW (Shiki_EDITOR_WINDOW), filename); |
|
|
|
|
g_free(filename); |
|
| 767 |
} |
} |
| 768 |
|
|
| 769 |
/* 本当に終了してもよろしいですか ? */ |
/* 本当に終了してもよろしいですか ? */ |
| 770 |
static gboolean not_yet_save_changes_really_quit(GtkTextBuffer *buffer) { |
static gboolean not_yet_save_changes_really_quit(GtkTextBuffer *buffer) { |
|
GtkWidget *dialog; |
|
|
gint resp; |
|
|
|
|
| 771 |
/* 変更が無ければそのまま終了 */ |
/* 変更が無ければそのまま終了 */ |
| 772 |
if(!gtk_text_buffer_get_modified(buffer)) return FALSE; |
if(!gtk_text_buffer_get_modified(buffer)) return FALSE; |
| 773 |
|
|
| 774 |
dialog = gtk_message_dialog_new(GTK_WINDOW(Shiki_EDITOR_WINDOW), |
return !Shiki_yes_or_no_p("バッファが変更されています.\nセーブしないで終了しますか ?"); |
|
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, |
|
|
GTK_BUTTONS_YES_NO, "バッファが変更されています.\nセーブしないで終了しますか ?"); |
|
|
|
|
|
resp = gtk_dialog_run(GTK_DIALOG(dialog)); |
|
|
gtk_widget_destroy(dialog); |
|
|
/* "delete_event" の返り値が FALSE ならば"destory" が発行され,window は破壊される */ |
|
|
if(GTK_RESPONSE_YES == resp) |
|
|
return FALSE; |
|
|
return TRUE; |
|
| 775 |
} |
} |
| 776 |
|
|
| 777 |
/* バッファがまだ保存されていないのに本当に終了するのかを尋ねる */ |
/* バッファがまだ保存されていないのに本当に終了するのかを尋ねる */ |
| 780 |
} |
} |
| 781 |
|
|
| 782 |
/* ファイルを開く */ |
/* ファイルを開く */ |
| 783 |
static void open_file(gchar *filename) { |
static void open_file(const gchar *filename) { |
| 784 |
gchar *text; |
gchar *text; |
| 785 |
gchar *utf8filename = g_locale_to_utf8(filename, -1, NULL, NULL, NULL); |
gchar *utf8filename = g_locale_to_utf8(filename, -1, NULL, NULL, NULL); |
| 786 |
GtkTextIter p; |
GtkTextIter p; |
| 789 |
/* g_file_get_contents(filename, &contents, &len, NULL); */ |
/* g_file_get_contents(filename, &contents, &len, NULL); */ |
| 790 |
|
|
| 791 |
/* 新しいバッファを開く */ |
/* 新しいバッファを開く */ |
| 792 |
get_buffer_create(g_strdup(filename)); |
Shiki_new_buffer_create(g_strdup(filename)); |
| 793 |
gtk_window_set_title (GTK_WINDOW (Shiki_EDITOR_WINDOW), filename); |
gtk_window_set_title (GTK_WINDOW (Shiki_EDITOR_WINDOW), filename); |
|
g_free(filename); |
|
| 794 |
|
|
| 795 |
Scm_Define(SCM_MODULE(Shiki_CURRENT_BUFFER_ENV), SCM_SYMBOL(SCM_INTERN("*filename*")), SCM_MAKE_STR_COPYING(utf8filename)); |
Scm_Define(SCM_MODULE(Shiki_CURRENT_BUFFER_ENV), SCM_SYMBOL(SCM_INTERN("*filename*")), SCM_MAKE_STR_COPYING(utf8filename)); |
| 796 |
g_free(utf8filename); |
g_free(utf8filename); |
| 823 |
|
|
| 824 |
/* ファイルをダイアログで指定して開く */ |
/* ファイルをダイアログで指定して開く */ |
| 825 |
static void open_file_handler() { |
static void open_file_handler() { |
| 826 |
gchar *filename = get_filename_from_dialog("File Selection"); |
const gchar *filename = Shiki_file_name_dialog("File Selection"); |
| 827 |
|
|
| 828 |
if(!filename) return; |
if(!filename) return; |
| 829 |
open_file(filename); |
open_file(filename); |
| 998 |
gtk_notebook_set_tab_pos(notebook, (notebook->tab_pos + 1) % 4); |
gtk_notebook_set_tab_pos(notebook, (notebook->tab_pos + 1) % 4); |
| 999 |
} |
} |
| 1000 |
|
|
|
/* 特定のキー操作のハンドリング */ |
|
|
|
|
|
/* カーソルの移動 ^npfb */ |
|
|
static void forward_current_buffer() { |
|
|
GtkTextIter p; |
|
|
gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER)); |
|
|
gtk_text_iter_forward_char(&p); |
|
|
gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p); |
|
|
} |
|
|
static void backward_current_buffer() { |
|
|
GtkTextIter p; |
|
|
gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER)); |
|
|
gtk_text_iter_backward_char(&p); |
|
|
gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p); |
|
|
} |
|
|
static void line_forward_current_buffer() { |
|
|
GtkTextIter p; |
|
|
gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER, &p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER)); |
|
|
gtk_text_view_forward_display_line(Shiki_CURRENT_TEXT_VIEW, &p); |
|
|
gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p); |
|
|
} |
|
|
static void line_backward_current_buffer() { |
|
|
GtkTextIter p; |
|
|
gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER)); |
|
|
gtk_text_view_backward_display_line(Shiki_CURRENT_TEXT_VIEW, &p); |
|
|
gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p); |
|
|
} |
|
|
|
|
| 1001 |
/* キーが離された */ |
/* キーが離された */ |
| 1002 |
static gboolean signal_key_release_handler (GtkWidget *notebook, GdkEventKey *event, gpointer contextid) { |
static gboolean signal_key_release_handler (GtkWidget *notebook, GdkEventKey *event, gpointer contextid) { |
| 1003 |
static gint metakey_pressed = 0; |
static gint metakey_pressed = 0; |
| 1078 |
} |
} |
| 1079 |
static void open_online_help() { |
static void open_online_help() { |
| 1080 |
GtkTextIter p; |
GtkTextIter p; |
| 1081 |
get_buffer_create(g_strdup("*help*")); |
Shiki_new_buffer_create(g_strdup("*help*")); |
| 1082 |
gtk_text_buffer_set_text(Shiki_CURRENT_TEXT_BUFFER, |
gtk_text_buffer_set_text(Shiki_CURRENT_TEXT_BUFFER, |
| 1083 |
"コマンドラインからの起動方法\n" |
"コマンドラインからの起動方法\n" |
| 1084 |
"$ ./shiki [file1 file2 ....]\n\n" |
"$ ./shiki [file1 file2 ....]\n\n" |
| 1239 |
/* TODO ここまで */ |
/* TODO ここまで */ |
| 1240 |
|
|
| 1241 |
icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_DELETE, iconsize), ""); |
icon = gtk_tool_button_new(gtk_image_new_from_stock (GTK_STOCK_DELETE, iconsize), ""); |
| 1242 |
g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(clear_current_buffer), G_OBJECT(Shiki_EDITOR_NOTEBOOK)); |
g_signal_connect(G_OBJECT(icon), "clicked", G_CALLBACK(clear_current_buffer_handler), NULL); |
| 1243 |
gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon)); |
gtk_container_add(GTK_CONTAINER (toolbar), GTK_WIDGET(icon)); |
| 1244 |
gtk_tool_item_set_tooltip(icon, toolbar_tips, "バッファの内容を全消去", |
gtk_tool_item_set_tooltip(icon, toolbar_tips, "バッファの内容を全消去", |
| 1245 |
"まだ内容が保存されていない場合でも警告しません"); |
"まだ内容が保存されていない場合でも警告しません"); |