mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-29 20:34:16 +01:00
Make test script. Change .src.md file's spec.
This commit is contained in:
parent
c2d1873d59
commit
1b8e407d8d
28 changed files with 1147 additions and 411 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -17,6 +17,7 @@ src/tfe5/hello.txt
|
|||
src/menu/a.out
|
||||
src/color/_build
|
||||
src/turtle/_build
|
||||
src/temp
|
||||
|
||||
html/*
|
||||
latex/*
|
||||
|
|
|
@ -21,7 +21,7 @@ This file is written in markdown language, of which the file has `.md` suffix.
|
|||
There are several kinds of markdown language.
|
||||
`Readme.md` uses 'github flavored markdown', which is often shortened as GFM.
|
||||
Markdown files in the top directory also written in GFM.
|
||||
If you are not familiar with it, refer the website [github flavoer markdown spec](https://github.github.com/gfm/).
|
||||
If you are not familiar with it, refer the website [github flavor markdown spec](https://github.github.com/gfm/).
|
||||
|
||||
## Pandoc's markdown
|
||||
|
||||
|
@ -31,84 +31,148 @@ This type of markdown is used to generate html and latex files in this tutorial.
|
|||
|
||||
## Src.md file
|
||||
|
||||
Src.md is similar to markdown but it has two commands which isn't included in markdown syntax.
|
||||
They are @@@ command and $$$ command.
|
||||
Src.md is similar to markdown but it has a command which isn't included in markdown syntax.
|
||||
It is @@@ command.
|
||||
The command starts at a line begins with "@@@" and ends at a line begins with "@@@".
|
||||
For example,
|
||||
|
||||
@@@ C_source_file [function_list]
|
||||
~~~
|
||||
@@@include
|
||||
tfeapplication.c
|
||||
@@@
|
||||
~~~
|
||||
|
||||
This command includes the C source file, but if a function list is given, only the functions in the C source file are included.
|
||||
If no function list is given, the command can include any text files even it is not C source file.
|
||||
There are three types of @@@ command.
|
||||
|
||||
$$$
|
||||
shell command
|
||||
... ...
|
||||
$$$
|
||||
### @@@include
|
||||
|
||||
This command executes the shell command and substitutes the strings in the standard output for the lines between $$$ inclusive.
|
||||
This type of @@@ command starts with a line begins "@@@include".
|
||||
|
||||
These two commands are carried out by scripts src2md.rb, which is described in the next subsection.
|
||||
~~~
|
||||
@@@include
|
||||
tfeapplication.c
|
||||
@@@
|
||||
~~~
|
||||
|
||||
This command replaces itself with the text read from the C source file.
|
||||
If a function list follows the filename, only the functions in the C source file are read.
|
||||
If no function list is given, the command can read any text files even it is not C source file.
|
||||
|
||||
~~~
|
||||
@@@include
|
||||
tfeapplication.c main startup
|
||||
@@@
|
||||
~~~
|
||||
|
||||
~~~
|
||||
@@@include
|
||||
lib_src2md.rb
|
||||
@@@
|
||||
~~~
|
||||
|
||||
The inserted text becomes fence code block.
|
||||
|
||||
~~~C
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
... ...
|
||||
}
|
||||
~~~
|
||||
|
||||
The string ("C" in the example above) follows the first fence is called info string.
|
||||
Info string is usually a language like C, ruby, xml and so on.
|
||||
This string is decided with the filename extension.
|
||||
|
||||
A line number is inserted at the top of each line in the code block.
|
||||
If you don't want to insert it, give "-N" option to @@@include command.
|
||||
|
||||
Options:
|
||||
|
||||
- "-n": Inserts a line number at the top of each line (default).
|
||||
- "-N": No line number is inserted.
|
||||
|
||||
This command have two advantages.
|
||||
|
||||
1. Less typing.
|
||||
2. You don't need to modify your src.md file, even if the C source file is modified.
|
||||
|
||||
### @@@shell
|
||||
|
||||
This type of @@@ command starts with a line begins "@@@shell".
|
||||
|
||||
~~~
|
||||
@@@shell
|
||||
shell command
|
||||
... ...
|
||||
@@@
|
||||
~~~
|
||||
|
||||
This command replaces itself with:
|
||||
|
||||
- the shell command
|
||||
- the standard output from the shell command
|
||||
|
||||
For example,
|
||||
|
||||
~~~
|
||||
@@@shell
|
||||
wc Rakefile
|
||||
@@@
|
||||
~~~
|
||||
|
||||
This is converted to:
|
||||
|
||||
~~~
|
||||
$ wc Rakefile
|
||||
164 475 4971 Rakefile
|
||||
~~~
|
||||
|
||||
### @@@if series
|
||||
|
||||
This type of @@@ command starts with a line begins "@@@if", "@@@elif", "@@@else" or "@@@end".
|
||||
This command is similar to "#if", "#elif", #else" and "#end" directives in C preprocessor.
|
||||
For example,
|
||||
|
||||
~~~
|
||||
@@@if gfm
|
||||
Refer to [tfetextview API reference](tfetextview/tfetextview_doc.md)
|
||||
@@@elif html
|
||||
Refer to [tfetextview API reference](tfetextview_doc.html)
|
||||
@@@elif latex
|
||||
Refer to tfetextview API reference in appendix.
|
||||
@@@end
|
||||
~~~
|
||||
|
||||
Conditions follow "@@@if" or "@@@elif".
|
||||
They are "gfm", "html" or "latex" so far.
|
||||
Other words or expressions may be available in the future version.
|
||||
|
||||
## Conversion
|
||||
|
||||
A ruby script src2md converts src.md file to md file.
|
||||
The @@@ commands are carried out by scripts src2md.rb.
|
||||
In addition, some conversion is made by srd2md.rb.
|
||||
|
||||
ruby src2md.rb src.md_file md_file
|
||||
|
||||
This script recognizes and carrys out the commands described in the previous subsection.
|
||||
For example, it is assumed that there are two files sample.src.md and sample.c, which have contents as follows.
|
||||
|
||||
$ cat sample.src.md
|
||||
The following is the contents of the file 'sample.c'.
|
||||
|
||||
@@@ sample.c
|
||||
|
||||
$ cat sample.c
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
printf("Hello world.\n");
|
||||
}
|
||||
|
||||
Now, convert sample.src.md to a markdown file sample.md.
|
||||
|
||||
$ ruby src2md.rb sample.src.md sample.md
|
||||
$ cat sample.md
|
||||
The following is the contents of the file 'sample.c'.
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
printf("Hello world.\n");
|
||||
}
|
||||
|
||||
Compare sample.src.md and sample.md.
|
||||
The contents of sample.c is substituted for the line `@@@ sample.c`.
|
||||
In addition four spaces are added at the top of each line of sample.c.
|
||||
|
||||
These two commands have two advantages.
|
||||
|
||||
1. Less typing.
|
||||
2. You don't need to modify your src.md file, even if the C sourcefile, which is included by @@@ command, is modified.
|
||||
In the same way, any upgrade of the shell commands described between $$$ commands doesn't affect the src.md file.
|
||||
- Relative links are changed according to the change of base directory.
|
||||
- Size option in image link is left out when the destination is GFM or html.
|
||||
- Relative link is left out when the destination is latex.
|
||||
- Lines in fence code block are folded when the destination is latex.
|
||||
|
||||
There's a method `src2md` in the `lib/lib_src2md.rb` script.
|
||||
This method converts src.md file into md file.
|
||||
This method is also used in other ruby scripts like Rakefile.
|
||||
This method is used in `srd2md.rb` and `Rakefile`.
|
||||
|
||||
## Directory structure
|
||||
|
||||
There are six directories under `gtk4_tutorial` directory.
|
||||
They are `gfm`, `src`, `image`, `html`, `latex` and `lib`.
|
||||
Three directories `gfm`, `html` and `latex` are the destination directores for GFM, html and latex files respectively.
|
||||
Three directories `gfm`, `html` and `latex` are the destination directories for GFM, html and latex files respectively.
|
||||
It is possible that these three directories don't exist before the conversion.
|
||||
|
||||
- src: This directory contains src.md files and C-related source files.
|
||||
- image: This directory contains image files like png or jpg.
|
||||
- gfm: This directory is empty at first. A ruby script will convert src.md files to GFM files and store them in this directory.
|
||||
- html: This directory is empty at first. A ruby script will convert src.md files to html files and store them in this directory.
|
||||
- latex: This directory is empty at first. A ruby script will convert src.md files to latexl files and store them in this directory.
|
||||
- latex: This directory is empty at first. A ruby script will convert src.md files to latex files and store them in this directory.
|
||||
- lib: This directory includes ruby library files.
|
||||
|
||||
## Src and top directories
|
||||
|
@ -126,8 +190,9 @@ Rake carries out the conversion according to the instruction written in Rakefile
|
|||
|
||||
## The name of files in src directory
|
||||
|
||||
Each file in src directory is a section of the whole document.
|
||||
The name of the files are "sec", number of the section and ".src.md" suffix.
|
||||
Each file in src directory is an abstract or section of the whole document.
|
||||
The name of the abstract file is "abstract.src.md".
|
||||
The name of the section files are "sec", number of the section and ".src.md" suffix.
|
||||
For example, "sec1.src.md", "sec5.src.md" or "sec12.src.md".
|
||||
They are the files correspond to section 1, section 5 and section 12 respectively.
|
||||
|
||||
|
@ -184,7 +249,7 @@ For example,
|
|||
|
||||
![sample image](../image/sample_image.png){width=10cm height=6cm}
|
||||
|
||||
The size between left brace abd right brace is used in latex file and it is not fit to GFM syntax.
|
||||
The size between left brace and right brace is used in latex file and it is not fit to GFM syntax.
|
||||
So the size is removed in the conversion above.
|
||||
|
||||
If a src.md file has relative URL link, it will be changed by conversion.
|
||||
|
@ -251,4 +316,3 @@ You can generate pdf file by typing `rake pdf`.
|
|||
|
||||
$ rake pdf
|
||||
|
||||
|
24
gfm/sec15.md
24
gfm/sec15.md
|
@ -660,17 +660,19 @@ It is a good practice for you to add more features.
|
|||
|
||||
## Total number of lines, words and characters
|
||||
|
||||
$ LANG=C wc tfe5/meson.build tfe5/tfeapplication.c tfe5/tfe.gresource.xml tfe5/tfe.h tfe5/tfenotebook.c tfe5/tfenotebook.h tfetextview/tfetextview.c tfetextview/tfetextview.h tfe5/tfe.ui
|
||||
10 17 294 tfe5/meson.build
|
||||
117 348 3576 tfe5/tfeapplication.c
|
||||
6 9 153 tfe5/tfe.gresource.xml
|
||||
4 6 87 tfe5/tfe.h
|
||||
117 325 3064 tfe5/tfenotebook.c
|
||||
12 17 196 tfe5/tfenotebook.h
|
||||
217 637 7725 tfetextview/tfetextview.c
|
||||
35 60 701 tfetextview/tfetextview.h
|
||||
64 105 2266 tfe5/tfe.ui
|
||||
582 1524 18062 total
|
||||
~~~
|
||||
$ LANG=C wc tfe5/meson.build tfe5/tfeapplication.c tfe5/tfe.gresource.xml tfe5/tfe.h tfe5/tfenotebook.c tfe5/tfenotebook.h tfetextview/tfetextview.c tfetextview/tfetextview.h tfe5/tfe.ui
|
||||
10 17 294 tfe5/meson.build
|
||||
117 348 3576 tfe5/tfeapplication.c
|
||||
6 9 153 tfe5/tfe.gresource.xml
|
||||
4 6 87 tfe5/tfe.h
|
||||
117 325 3064 tfe5/tfenotebook.c
|
||||
12 17 196 tfe5/tfenotebook.h
|
||||
217 637 7725 tfetextview/tfetextview.c
|
||||
35 60 701 tfetextview/tfetextview.h
|
||||
64 105 2266 tfe5/tfe.ui
|
||||
582 1524 18062 total
|
||||
~~~
|
||||
|
||||
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 14](sec14.md), Next: [Section 16](sec16.md)
|
||||
|
|
84
gfm/sec4.md
84
gfm/sec4.md
|
@ -56,22 +56,24 @@ A window with a message "Hello." appears.
|
|||
There's only a little change between `pr4.c` and `lb1.c`.
|
||||
Diff is a good program to know the difference between two files.
|
||||
|
||||
$ cd misc; diff pr4.c lb1.c
|
||||
5a6
|
||||
> GtkWidget *lab;
|
||||
8c9
|
||||
< gtk_window_set_title (GTK_WINDOW (win), "pr4");
|
||||
---
|
||||
> gtk_window_set_title (GTK_WINDOW (win), "lb1");
|
||||
9a11,14
|
||||
>
|
||||
> lab = gtk_label_new ("Hello.");
|
||||
> gtk_window_set_child (GTK_WINDOW (win), lab);
|
||||
>
|
||||
18c23
|
||||
< app = gtk_application_new ("com.github.ToshioCP.pr4", G_APPLICATION_FLAGS_NONE);
|
||||
---
|
||||
> app = gtk_application_new ("com.github.ToshioCP.lb1", G_APPLICATION_FLAGS_NONE);
|
||||
~~~
|
||||
$ cd misc; diff pr4.c lb1.c
|
||||
5a6
|
||||
> GtkWidget *lab;
|
||||
8c9
|
||||
< gtk_window_set_title (GTK_WINDOW (win), "pr4");
|
||||
---
|
||||
> gtk_window_set_title (GTK_WINDOW (win), "lb1");
|
||||
9a11,14
|
||||
>
|
||||
> lab = gtk_label_new ("Hello.");
|
||||
> gtk_window_set_child (GTK_WINDOW (win), lab);
|
||||
>
|
||||
18c23
|
||||
< app = gtk_application_new ("com.github.ToshioCP.pr4", G_APPLICATION_FLAGS_NONE);
|
||||
---
|
||||
> app = gtk_application_new ("com.github.ToshioCP.lb1", G_APPLICATION_FLAGS_NONE);
|
||||
~~~
|
||||
|
||||
This tells us:
|
||||
|
||||
|
@ -187,30 +189,32 @@ The following code is `lb3.c`.
|
|||
|
||||
And the difference between `lb2.c` and `lb3.c` is as follows.
|
||||
|
||||
$ cd misc; diff lb2.c lb3.c
|
||||
5c5,6
|
||||
< g_print ("Clicked.\n");
|
||||
---
|
||||
> GtkWindow *win = GTK_WINDOW (user_data);
|
||||
> gtk_window_destroy (win);
|
||||
14c15
|
||||
< gtk_window_set_title (GTK_WINDOW (win), "lb2");
|
||||
---
|
||||
> gtk_window_set_title (GTK_WINDOW (win), "lb3");
|
||||
17c18
|
||||
< btn = gtk_button_new_with_label ("Click me");
|
||||
---
|
||||
> btn = gtk_button_new_with_label ("Quit");
|
||||
19c20
|
||||
< g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL);
|
||||
---
|
||||
> g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win);
|
||||
29c30
|
||||
< app = gtk_application_new ("com.github.ToshioCP.lb2", G_APPLICATION_FLAGS_NONE);
|
||||
---
|
||||
> app = gtk_application_new ("com.github.ToshioCP.lb3", G_APPLICATION_FLAGS_NONE);
|
||||
35d35
|
||||
<
|
||||
~~~
|
||||
$ cd misc; diff lb2.c lb3.c
|
||||
5c5,6
|
||||
< g_print ("Clicked.\n");
|
||||
---
|
||||
> GtkWindow *win = GTK_WINDOW (user_data);
|
||||
> gtk_window_destroy (win);
|
||||
14c15
|
||||
< gtk_window_set_title (GTK_WINDOW (win), "lb2");
|
||||
---
|
||||
> gtk_window_set_title (GTK_WINDOW (win), "lb3");
|
||||
17c18
|
||||
< btn = gtk_button_new_with_label ("Click me");
|
||||
---
|
||||
> btn = gtk_button_new_with_label ("Quit");
|
||||
19c20
|
||||
< g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL);
|
||||
---
|
||||
> g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win);
|
||||
29c30
|
||||
< app = gtk_application_new ("com.github.ToshioCP.lb2", G_APPLICATION_FLAGS_NONE);
|
||||
---
|
||||
> app = gtk_application_new ("com.github.ToshioCP.lb3", G_APPLICATION_FLAGS_NONE);
|
||||
35d35
|
||||
<
|
||||
~~~
|
||||
|
||||
The change is:
|
||||
|
||||
|
|
32
gfm/sec5.md
32
gfm/sec5.md
|
@ -92,21 +92,23 @@ What we need to do is:
|
|||
Modify `tfv1.c` and save it as `tfv2.c`.
|
||||
The difference between these two files is very little.
|
||||
|
||||
$ cd tfv; diff tfv1.c tfv2.c
|
||||
5a6
|
||||
> GtkWidget *scr;
|
||||
24a26,28
|
||||
> scr = gtk_scrolled_window_new ();
|
||||
> gtk_window_set_child (GTK_WINDOW (win), scr);
|
||||
>
|
||||
30c34
|
||||
< gtk_window_set_child (GTK_WINDOW (win), tv);
|
||||
---
|
||||
> gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
40c44
|
||||
< app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
|
||||
---
|
||||
> app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
|
||||
~~~
|
||||
$ cd tfv; diff tfv1.c tfv2.c
|
||||
5a6
|
||||
> GtkWidget *scr;
|
||||
24a26,28
|
||||
> scr = gtk_scrolled_window_new ();
|
||||
> gtk_window_set_child (GTK_WINDOW (win), scr);
|
||||
>
|
||||
30c34
|
||||
< gtk_window_set_child (GTK_WINDOW (win), tv);
|
||||
---
|
||||
> gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
40c44
|
||||
< app = gtk_application_new ("com.github.ToshioCP.tfv1", G_APPLICATION_FLAGS_NONE);
|
||||
---
|
||||
> app = gtk_application_new ("com.github.ToshioCP.tfv2", G_APPLICATION_FLAGS_NONE);
|
||||
~~~
|
||||
|
||||
Though you can modify the source file by this diff output, It's good for you to show `tfv2.c`.
|
||||
|
||||
|
|
172
gfm/sec8.md
172
gfm/sec8.md
|
@ -236,64 +236,66 @@ All the widgets are connected based on the parent-children relationship describe
|
|||
We only need `win` and `nb` for the program after this, so we don't need to take out any other widgets.
|
||||
This reduces lines in the C source file.
|
||||
|
||||
$ cd tfe; diff tfe2.c tfe3.c
|
||||
58a59
|
||||
> GtkBuilder *build;
|
||||
60,103c61,65
|
||||
< GtkWidget *boxv;
|
||||
< GtkWidget *boxh;
|
||||
< GtkWidget *dmy1;
|
||||
< GtkWidget *dmy2;
|
||||
< GtkWidget *dmy3;
|
||||
< GtkWidget *btnn; /* button for new */
|
||||
< GtkWidget *btno; /* button for open */
|
||||
< GtkWidget *btns; /* button for save */
|
||||
< GtkWidget *btnc; /* button for close */
|
||||
<
|
||||
< win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
< gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
||||
< gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||
<
|
||||
< boxv = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
< gtk_window_set_child (GTK_WINDOW (win), boxv);
|
||||
<
|
||||
< boxh = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
< gtk_box_append (GTK_BOX (boxv), boxh);
|
||||
<
|
||||
< dmy1 = gtk_label_new(NULL); /* dummy label for left space */
|
||||
< gtk_label_set_width_chars (GTK_LABEL (dmy1), 10);
|
||||
< dmy2 = gtk_label_new(NULL); /* dummy label for center space */
|
||||
< gtk_widget_set_hexpand (dmy2, TRUE);
|
||||
< dmy3 = gtk_label_new(NULL); /* dummy label for right space */
|
||||
< gtk_label_set_width_chars (GTK_LABEL (dmy3), 10);
|
||||
< btnn = gtk_button_new_with_label ("New");
|
||||
< btno = gtk_button_new_with_label ("Open");
|
||||
< btns = gtk_button_new_with_label ("Save");
|
||||
< btnc = gtk_button_new_with_label ("Close");
|
||||
<
|
||||
< gtk_box_append (GTK_BOX (boxh), dmy1);
|
||||
< gtk_box_append (GTK_BOX (boxh), btnn);
|
||||
< gtk_box_append (GTK_BOX (boxh), btno);
|
||||
< gtk_box_append (GTK_BOX (boxh), dmy2);
|
||||
< gtk_box_append (GTK_BOX (boxh), btns);
|
||||
< gtk_box_append (GTK_BOX (boxh), btnc);
|
||||
< gtk_box_append (GTK_BOX (boxh), dmy3);
|
||||
<
|
||||
< nb = gtk_notebook_new ();
|
||||
< gtk_widget_set_hexpand (nb, TRUE);
|
||||
< gtk_widget_set_vexpand (nb, TRUE);
|
||||
< gtk_box_append (GTK_BOX (boxv), nb);
|
||||
<
|
||||
---
|
||||
> build = gtk_builder_new_from_file ("tfe3.ui");
|
||||
> win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
> gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
> nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
|
||||
> g_object_unref(build);
|
||||
138c100
|
||||
< app = gtk_application_new ("com.github.ToshioCP.tfe2", G_APPLICATION_HANDLES_OPEN);
|
||||
---
|
||||
> app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
|
||||
~~~
|
||||
$ cd tfe; diff tfe2.c tfe3.c
|
||||
58a59
|
||||
> GtkBuilder *build;
|
||||
60,103c61,65
|
||||
< GtkWidget *boxv;
|
||||
< GtkWidget *boxh;
|
||||
< GtkWidget *dmy1;
|
||||
< GtkWidget *dmy2;
|
||||
< GtkWidget *dmy3;
|
||||
< GtkWidget *btnn; /* button for new */
|
||||
< GtkWidget *btno; /* button for open */
|
||||
< GtkWidget *btns; /* button for save */
|
||||
< GtkWidget *btnc; /* button for close */
|
||||
<
|
||||
< win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
< gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
||||
< gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||||
<
|
||||
< boxv = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
< gtk_window_set_child (GTK_WINDOW (win), boxv);
|
||||
<
|
||||
< boxh = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
< gtk_box_append (GTK_BOX (boxv), boxh);
|
||||
<
|
||||
< dmy1 = gtk_label_new(NULL); /* dummy label for left space */
|
||||
< gtk_label_set_width_chars (GTK_LABEL (dmy1), 10);
|
||||
< dmy2 = gtk_label_new(NULL); /* dummy label for center space */
|
||||
< gtk_widget_set_hexpand (dmy2, TRUE);
|
||||
< dmy3 = gtk_label_new(NULL); /* dummy label for right space */
|
||||
< gtk_label_set_width_chars (GTK_LABEL (dmy3), 10);
|
||||
< btnn = gtk_button_new_with_label ("New");
|
||||
< btno = gtk_button_new_with_label ("Open");
|
||||
< btns = gtk_button_new_with_label ("Save");
|
||||
< btnc = gtk_button_new_with_label ("Close");
|
||||
<
|
||||
< gtk_box_append (GTK_BOX (boxh), dmy1);
|
||||
< gtk_box_append (GTK_BOX (boxh), btnn);
|
||||
< gtk_box_append (GTK_BOX (boxh), btno);
|
||||
< gtk_box_append (GTK_BOX (boxh), dmy2);
|
||||
< gtk_box_append (GTK_BOX (boxh), btns);
|
||||
< gtk_box_append (GTK_BOX (boxh), btnc);
|
||||
< gtk_box_append (GTK_BOX (boxh), dmy3);
|
||||
<
|
||||
< nb = gtk_notebook_new ();
|
||||
< gtk_widget_set_hexpand (nb, TRUE);
|
||||
< gtk_widget_set_vexpand (nb, TRUE);
|
||||
< gtk_box_append (GTK_BOX (boxv), nb);
|
||||
<
|
||||
---
|
||||
> build = gtk_builder_new_from_file ("tfe3.ui");
|
||||
> win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
> gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
> nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
|
||||
> g_object_unref(build);
|
||||
138c100
|
||||
< app = gtk_application_new ("com.github.ToshioCP.tfe2", G_APPLICATION_HANDLES_OPEN);
|
||||
---
|
||||
> app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
|
||||
~~~
|
||||
|
||||
`60,103c61,65` means 42 (=103-60+1) lines change to 5 (=65-61+1) lines.
|
||||
Therefore 37 lines are reduced.
|
||||
|
@ -419,32 +421,34 @@ If you want to add more files, then insert them between line 4 and 5.
|
|||
Save this xml text to `tfe3.gresource.xml`.
|
||||
The gresource compiler `glib-compile-resources` shows its usage with the argument `--help`.
|
||||
|
||||
$ LANG=C glib-compile-resources --help
|
||||
Usage:
|
||||
glib-compile-resources [OPTION?] FILE
|
||||
|
||||
Compile a resource specification into a resource file.
|
||||
Resource specification files have the extension .gresource.xml,
|
||||
and the resource file have the extension called .gresource.
|
||||
|
||||
Help Options:
|
||||
-h, --help Show help options
|
||||
|
||||
Application Options:
|
||||
--version Show program version and exit
|
||||
--target=FILE Name of the output file
|
||||
--sourcedir=DIRECTORY The directories to load files referenced in FILE from (default: current directory)
|
||||
--generate Generate output in the format selected for by the target filename extension
|
||||
--generate-header Generate source header
|
||||
--generate-source Generate source code used to link in the resource file into your code
|
||||
--generate-dependencies Generate dependency list
|
||||
--dependency-file=FILE Name of the dependency file to generate
|
||||
--generate-phony-targets Include phony targets in the generated dependency file
|
||||
--manual-register Don?t automatically create and register resource
|
||||
--internal Don?t export functions; declare them G_GNUC_INTERNAL
|
||||
--external-data Don?t embed resource data in the C file; assume it's linked externally instead
|
||||
--c-name C identifier name used for the generated source code
|
||||
|
||||
~~~
|
||||
$ LANG=C glib-compile-resources --help
|
||||
Usage:
|
||||
glib-compile-resources [OPTION?] FILE
|
||||
|
||||
Compile a resource specification into a resource file.
|
||||
Resource specification files have the extension .gresource.xml,
|
||||
and the resource file have the extension called .gresource.
|
||||
|
||||
Help Options:
|
||||
-h, --help Show help options
|
||||
|
||||
Application Options:
|
||||
--version Show program version and exit
|
||||
--target=FILE Name of the output file
|
||||
--sourcedir=DIRECTORY The directories to load files referenced in FILE from (default: current directory)
|
||||
--generate Generate output in the format selected for by the target filename extension
|
||||
--generate-header Generate source header
|
||||
--generate-source Generate source code used to link in the resource file into your code
|
||||
--generate-dependencies Generate dependency list
|
||||
--dependency-file=FILE Name of the dependency file to generate
|
||||
--generate-phony-targets Include phony targets in the generated dependency file
|
||||
--manual-register Don?t automatically create and register resource
|
||||
--internal Don?t export functions; declare them G_GNUC_INTERNAL
|
||||
--external-data Don?t embed resource data in the C file; assume it's linked externally instead
|
||||
--c-name C identifier name used for the generated source code
|
||||
|
||||
~~~
|
||||
|
||||
Now run the compiler.
|
||||
|
||||
|
|
|
@ -1,44 +1,45 @@
|
|||
class Sec_file < String
|
||||
def initialize path
|
||||
if path.instance_of?(String) && File.exist?(path)
|
||||
@name = File.basename path
|
||||
@dirname = File.dirname path
|
||||
unless @name =~ /^sec\d+(\.\d+)?\.(src\.md|md|html|tex)$/
|
||||
raise "Sec_file class initialization error: #{path} is not Sec_file object name."
|
||||
end
|
||||
super(path)
|
||||
else
|
||||
raise "Sec_file class initialization error: file #{path} is not exist."
|
||||
unless path.instance_of?(String)
|
||||
raise "Sec_file class initialization error: The argument is not String type."
|
||||
end
|
||||
end
|
||||
def type
|
||||
@name.match(/\.(src\.md|md|html|tex)$/)[1]
|
||||
unless File.exist?(path)
|
||||
raise "Sec_file class initialization error: File #{path} is not exist."
|
||||
end
|
||||
unless path =~ /sec\d+(\.\d+)?\.src\.md$/
|
||||
raise "Sec_file class initialization error: The argment \"#{path}\" doesn't have secXX.src.md form. XX are digits."
|
||||
end
|
||||
@name = File.basename path
|
||||
@dirname = File.dirname path
|
||||
super(path)
|
||||
end
|
||||
def path
|
||||
self
|
||||
end
|
||||
def name
|
||||
def basename
|
||||
@name
|
||||
end
|
||||
def dirname
|
||||
@dirname
|
||||
end
|
||||
def c_files
|
||||
if self.type != "src.md"
|
||||
return []
|
||||
else
|
||||
buf = IO.readlines(self)
|
||||
files = []
|
||||
buf.each do |line|
|
||||
if line =~ /^@@@ (\S+)/
|
||||
files << @dirname+"/"+$1
|
||||
buf = IO.readlines(self)
|
||||
files = []
|
||||
in_include = false
|
||||
buf.each do |line|
|
||||
if in_include
|
||||
if line == "@@@\n"
|
||||
in_include = false
|
||||
else
|
||||
files << @dirname+"/"+line.match(/^ *(\S*)/)[1]
|
||||
end
|
||||
elsif line == "@@@include\n"
|
||||
in_include = true
|
||||
else
|
||||
# lines out of @@@include command is thrown away.
|
||||
end
|
||||
files
|
||||
end
|
||||
end
|
||||
def to_srcmd
|
||||
@name.gsub(/\.(src\.md|md|html|tex)$/, ".src.md")
|
||||
files
|
||||
end
|
||||
def to_md
|
||||
@name.gsub(/\.(src\.md|md|html|tex)$/, ".md")
|
||||
|
@ -75,12 +76,12 @@ class Sec_file < String
|
|||
if n.instance_of?(Integer) || n.instance_of?(Float)
|
||||
n = n.to_i if n == n.floor
|
||||
old = self
|
||||
new = self.gsub(/\d+(\.\d+)?(\.(src\.md|md|html|tex)$)/, "#{n}\\2")
|
||||
new = self.gsub(/\d+(\.\d+)?\.src\.md$/, "#{n}.src.md")
|
||||
if old != new
|
||||
File.rename old, new
|
||||
self.replace new
|
||||
@name = File.basename self
|
||||
@dirname = File.dirname self
|
||||
@name = File.basename new
|
||||
@dirname = File.dirname new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -119,35 +120,22 @@ class Sec_files < Array
|
|||
|
||||
private
|
||||
def any_diff? tbl
|
||||
diff = false
|
||||
tbl.each do |t|
|
||||
diff = true if t[2] == false
|
||||
end
|
||||
diff
|
||||
tbl.find_index { |row| row[2] == false }
|
||||
end
|
||||
def try_renum tbl
|
||||
changed = false
|
||||
(self.size - 1).downto 0 do |i|
|
||||
if tbl[i][2] == false
|
||||
n = tbl[i][1] # number to substitute
|
||||
found = false
|
||||
self.each do |sec_file|
|
||||
if sec_file != self[i] && sec_file.to_f == n
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
found = self.find_index { |sec_file| sec_file != self && sec_file.to_f == n }
|
||||
unless found # OK to replace
|
||||
self[i].renum! n
|
||||
tbl[i][2] = true
|
||||
# tbl[0] (old number (String) is kept in the array 'tbl')
|
||||
changed = true
|
||||
self.each do |sec_file|
|
||||
buf_n = []
|
||||
buf = IO.readlines sec_file
|
||||
buf.each do |line|
|
||||
buf_n << line.gsub(/((S|s)ection *)#{tbl[i][0]}/, "\\1#{n}").gsub(/((S|s)ec *)#{tbl[i][0]}/, "\\1#{n}")
|
||||
end
|
||||
buf_n = buf.map { |line| line.gsub(/((S|s)ection *)#{tbl[i][0]}/, "\\1#{n}").gsub(/((S|s)ec *)#{tbl[i][0]}/, "\\1#{n}") }
|
||||
IO.write sec_file, buf_n.join
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ require 'pathname'
|
|||
# (sec13.tex)
|
||||
# \hypertarget{tfeapplication.c}{%
|
||||
# \section{tfeapplication.c}\label{tfeapplication.c}}
|
||||
# If you click the text 'Section 13' in sec11.tex, then you can move to '13 tfeapplication.c', which is section 13 in sec13.tex.
|
||||
# If you click the text 'Section 13' in sec11.tex, then you can move to '13 tfeapplication.c' ("13 " is automatically added by latex), which is section 13 in sec13.tex.
|
||||
|
||||
# The following lines are the original one in sec11.md and the result in sec11.tex, which is generated by pandoc.
|
||||
# (sec11.md)
|
||||
|
@ -40,7 +40,7 @@ require 'pathname'
|
|||
|
||||
# If the target is full URL, which means absolute URL begins with "http", no problem happens.
|
||||
|
||||
# This Rakefile just remove the links if its target is relative URL.
|
||||
# This script just remove the links if its target is relative URL.
|
||||
# If you want to revive the link with relative URL, refer the description above.
|
||||
|
||||
# ---- Folding verbatim lines ----
|
||||
|
@ -63,84 +63,134 @@ require 'pathname'
|
|||
# Makefile => makefile
|
||||
|
||||
def src2md srcmd, md, width
|
||||
# parameters:
|
||||
# srcmd: .src.md file's path. source
|
||||
# md: .md file's path. destination
|
||||
# width: maximum width of lines in fence code block
|
||||
src_buf = IO.readlines srcmd
|
||||
src_dir = File.dirname srcmd
|
||||
md_dir = File.dirname md
|
||||
type = File.basename md_dir # gfm, html or latex
|
||||
type = File.basename md_dir # type of the target. gfm, html or latex
|
||||
|
||||
md_buf = []
|
||||
comflag = false
|
||||
include_flag = ""
|
||||
shell_flag = false
|
||||
if_stat = 0
|
||||
src_buf.each do |line|
|
||||
if comflag
|
||||
if line == "$$$\n"
|
||||
comflag = false
|
||||
else
|
||||
md_buf << " $ "+line
|
||||
`cd #{src_dir}; #{line.chomp}`.each_line do |l|
|
||||
fold(l, width).each_line do |l2|
|
||||
md_buf << l2.gsub(/^/," ")
|
||||
end
|
||||
if include_flag == "-N" || include_flag == "-n"
|
||||
if line == "@@@\n"
|
||||
include_flag = false
|
||||
elsif line =~ /^ *(\S*) *(.*)$/
|
||||
c_file = $1
|
||||
c_functions = $2.strip.split(" ")
|
||||
if c_file =~ /^\// # absolute path
|
||||
c_file_buf = IO.readlines(c_file)
|
||||
else #relative path
|
||||
c_file_buf = IO.readlines(src_dir+"/"+c_file)
|
||||
end
|
||||
end
|
||||
elsif line == "$$$\n"
|
||||
comflag = true
|
||||
elsif line =~ /^@@@\s+(\S+)\s*(.*)$/
|
||||
c_file = $1
|
||||
c_functions = $2.strip.split(" ")
|
||||
if c_file =~ /^\// # absolute path
|
||||
c_file_buf = IO.readlines(c_file)
|
||||
else #relative path
|
||||
c_file_buf = IO.readlines(src_dir+"/"+c_file)
|
||||
end
|
||||
if c_functions.empty? # no functions are specified
|
||||
tmp_buf = c_file_buf
|
||||
else
|
||||
tmp_buf = []
|
||||
spc = false
|
||||
c_functions.each do |c_function|
|
||||
from = c_file_buf.find_index { |line| line =~ /^#{c_function} *\(/ }
|
||||
if ! from
|
||||
warn "ERROR!!! --- Didn't find #{c_function} in #{filename}. ---"
|
||||
break
|
||||
end
|
||||
to = from
|
||||
while to < c_file_buf.size do
|
||||
if c_file_buf[to] == "}\n"
|
||||
if c_functions.empty? # no functions are specified
|
||||
tmp_buf = c_file_buf
|
||||
else
|
||||
tmp_buf = []
|
||||
spc = false
|
||||
c_functions.each do |c_function|
|
||||
from = c_file_buf.find_index { |line| line =~ /^#{c_function} *\(/ }
|
||||
if ! from
|
||||
warn "ERROR!!! --- Didn't find #{c_function} in #{filename}. ---"
|
||||
break
|
||||
end
|
||||
to += 1
|
||||
end
|
||||
n = from-1
|
||||
if spc
|
||||
tmp_buf << "\n"
|
||||
else
|
||||
spc = true
|
||||
end
|
||||
while n <= to do
|
||||
tmp_buf << c_file_buf[n]
|
||||
n += 1
|
||||
to = from
|
||||
while to < c_file_buf.size do
|
||||
if c_file_buf[to] == "}\n"
|
||||
break
|
||||
end
|
||||
to += 1
|
||||
end
|
||||
n = from-1
|
||||
if spc
|
||||
tmp_buf << "\n"
|
||||
else
|
||||
spc = true
|
||||
end
|
||||
while n <= to do
|
||||
tmp_buf << c_file_buf[n]
|
||||
n += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
md_buf << "~~~#{lang(c_file)}\n"
|
||||
ln_width = tmp_buf.size.to_s.length
|
||||
n = 1
|
||||
tmp_buf.each do |l|
|
||||
if include_flag == "-n"
|
||||
l = sprintf("%#{ln_width}d %s", n, l)
|
||||
end
|
||||
fold(l, width).each_line do |l2|
|
||||
md_buf << l2
|
||||
end
|
||||
n += 1
|
||||
end
|
||||
md_buf << "~~~\n"
|
||||
end
|
||||
md_buf << "~~~#{lang(c_file)}\n"
|
||||
ln_width = tmp_buf.size.to_s.length
|
||||
n = 1
|
||||
tmp_buf.each do |l|
|
||||
l = sprintf("%#{ln_width}d %s", n, l)
|
||||
fold(l, width).each_line do |l2|
|
||||
elsif shell_flag
|
||||
if line == "@@@\n"
|
||||
shell_flag = false
|
||||
else
|
||||
md_buf << "~~~\n"
|
||||
fold("$ #{line}", width).each_line do |l2|
|
||||
md_buf << l2
|
||||
end
|
||||
n += 1
|
||||
`cd #{src_dir}; #{line.chomp}`.each_line do |l|
|
||||
fold(l, width).each_line do |l2|
|
||||
md_buf << l2
|
||||
end
|
||||
end
|
||||
md_buf << "~~~\n"
|
||||
end
|
||||
md_buf << "~~~\n"
|
||||
else
|
||||
line = change_rel_link(line, src_dir, md_dir)
|
||||
if type == "latex" # remove relative link
|
||||
line.gsub!(/(^|[^!])\[([^\]]*)\]\((?~http)\)/,"\\1\\2")
|
||||
else # type == "gfm" or "html", then remove size option from link to image files.
|
||||
line.gsub!(/(!\[[^\]]*\]\([^\)]*\)) *{width *= *\d*(|\.\d*)cm *height *= *\d*(|\.\d*)cm}/,"\\1")
|
||||
elsif line =~ /^@@@if *(\w+)/ && if_stat == 0
|
||||
if_stat = type == $1 ? 1 : -1
|
||||
elsif line =~ /^@@@elif *(\w+)/
|
||||
if if_stat == 1
|
||||
if_stat = -2
|
||||
elsif if_stat == -1
|
||||
if_stat = type == $1 ? 3 : -3
|
||||
elsif if_stat == -2
|
||||
# if_stat is kept to be -2
|
||||
elsif if_stat == 3
|
||||
if_stat = -2
|
||||
elsif if_stat == -3
|
||||
if_stat = type == $1 ? 3 : -3
|
||||
end
|
||||
elsif line =~ /^@@@else/
|
||||
if if_stat == 1
|
||||
if_stat = -2
|
||||
elsif if_stat == -1
|
||||
if_stat = 2
|
||||
elsif if_stat == -2
|
||||
# if_stat is kept to be -2
|
||||
elsif if_stat == 3
|
||||
if_stat = -2
|
||||
elsif if_stat == -3
|
||||
if_stat = 2
|
||||
end
|
||||
elsif line =~ /^@@@end/
|
||||
if_stat = 0
|
||||
elsif if_stat >= 0
|
||||
if line == "@@@include\n" || line =~ /^@@@include *-n/
|
||||
include_flag = "-n"
|
||||
elsif line =~ /^@@@include *-N/
|
||||
include_flag = "-N"
|
||||
elsif line == "@@@shell\n"
|
||||
shell_flag = true
|
||||
else
|
||||
line = change_rel_link(line, src_dir, md_dir)
|
||||
if type == "latex" # remove relative link
|
||||
line.gsub!(/(^|[^!])\[([^\]]*)\]\((?~http)\)/,"\\1\\2")
|
||||
else # type == "gfm" or "html", then remove size option from link to image files.
|
||||
line.gsub!(/(!\[[^\]]*\]\([^\)]*\)) *{width *= *\d*(|\.\d*)cm *height *= *\d*(|\.\d*)cm}/,"\\1")
|
||||
end
|
||||
md_buf << line
|
||||
end
|
||||
md_buf << line
|
||||
end
|
||||
end
|
||||
IO.write(md,md_buf.join)
|
||||
|
@ -168,16 +218,13 @@ def change_rel_link line, org_dir, new_dir
|
|||
end
|
||||
|
||||
def fold line, width
|
||||
if width <= 0
|
||||
return line
|
||||
if line.instance_of?(String) && width.instance_of?(Integer) && width > 0
|
||||
n = (line.chomp.length - 1) / width
|
||||
n.downto(1) do |i|
|
||||
line.insert width*i, "\n"
|
||||
end
|
||||
end
|
||||
tmp = []
|
||||
while line.length > width
|
||||
tmp << line[0, width]+"\n"
|
||||
line = line[width .. -1]
|
||||
end
|
||||
tmp << line
|
||||
tmp.join
|
||||
line
|
||||
end
|
||||
|
||||
def lang file
|
||||
|
|
|
@ -98,7 +98,9 @@ The structure of `TfeTextView` is like the following diagram.
|
|||
|
||||
The function `tfe_text_view_new` generates a new TfeTextView instance.
|
||||
|
||||
@@@ tfetextview/tfetextview.c tfe_text_view_new
|
||||
@@@include
|
||||
tfetextview/tfetextview.c tfe_text_view_new
|
||||
@@@
|
||||
|
||||
When this function is run, the following procedure is gone through.
|
||||
|
||||
|
@ -113,7 +115,9 @@ Step four is done by the function `tfe_text_view_init`.
|
|||
> In the same way, `gtk_text_view_init`, `gtk_widget_init` and `g_object_init` is the initialization functions of GtkTextView, GtkWidget and GObject respectively.
|
||||
> You can find them in the GTK or GLib source files.
|
||||
|
||||
@@@ tfetextview/tfetextview.c tfe_text_view_init
|
||||
@@@include
|
||||
tfetextview/tfetextview.c tfe_text_view_init
|
||||
@@@
|
||||
|
||||
This function just initializes `tv->file` to be `NULL`.
|
||||
|
||||
|
@ -137,7 +141,9 @@ Class comprises mainly pointers to functions.
|
|||
Those functions are used by the object itself or its descendant objects.
|
||||
For example, GObject class is declared in `gobject.h` in GLib source files.
|
||||
|
||||
@@@ class_gobject.c
|
||||
@@@include
|
||||
class_gobject.c
|
||||
@@@
|
||||
|
||||
I'd like to explain some of the members.
|
||||
There's a pointer to the function `dispose` in line 22.
|
||||
|
@ -175,7 +181,9 @@ Let's look at all the classes from GObject, which is the top level object, to Tf
|
|||
|
||||
The following is extracts from the source files (not exactly the same).
|
||||
|
||||
@@@ classes.c
|
||||
@@@include
|
||||
classes.c
|
||||
@@@
|
||||
|
||||
- 105-107: This three lines are generated by the macro G\_DECLARE\_FINAL\_TYPE.
|
||||
So, they are not written in either `tfe_text_view.h` or `tfe_text_view.c`.
|
||||
|
@ -222,7 +230,9 @@ In the destruction process of TfeTextView, the reference count of widgets relate
|
|||
But GFile pointed by `tv->file` needs to decrease its reference count by one.
|
||||
You must write the code in the dispose handler `tfe_text_view_dispose`.
|
||||
|
||||
@@@ tfetextview/tfetextview.c tfe_text_view_dispose
|
||||
@@@include
|
||||
tfetextview/tfetextview.c tfe_text_view_dispose
|
||||
@@@
|
||||
|
||||
- 5,6: If `tv->file` points a GFile, decrease its reference count.
|
||||
`g_clear_object` decreases the reference count and assigns NULL to `tv->file`.
|
||||
|
|
|
@ -55,7 +55,9 @@ static guint tfe_text_view_signals[NUMBER_OF_SIGNALS];
|
|||
|
||||
Signal registration codes are written in the class initialization function.
|
||||
|
||||
@@@ tfetextview/tfetextview.c tfe_text_view_class_init
|
||||
@@@include
|
||||
tfetextview/tfetextview.c tfe_text_view_class_init
|
||||
@@@
|
||||
|
||||
- 6-15: Registers "change-file" signal.
|
||||
`g_signal_newv` function is used.
|
||||
|
|
|
@ -7,11 +7,15 @@ In this section I will explain functions in TfeTextView object.
|
|||
`tfe.h` is a top header file and it includes `gtk.h` and all the header files.
|
||||
C source files `tfeapplication.c` and `tfenotebook.c` include `tfe.h` at the beginning.
|
||||
|
||||
@@@ tfe5/tfe.h
|
||||
@@@include
|
||||
tfe5/tfe.h
|
||||
@@@
|
||||
|
||||
`../tfetextview/tfetextview.h` is a header file which describes the public functions in `tfetextview.c`.
|
||||
|
||||
@@@ tfetextview//tfetextview.h
|
||||
@@@include
|
||||
tfetextview//tfetextview.h
|
||||
@@@
|
||||
|
||||
- 1,2,35: Thanks to these three lines, the following lines are included only once.
|
||||
- 4: Includes gtk4 header files.
|
||||
|
@ -39,7 +43,9 @@ If an error occurs during the generation process, NULL is returned.
|
|||
|
||||
Each function is defined as follows.
|
||||
|
||||
@@@ tfetextview/tfetextview.c tfe_text_view_new_with_file tfe_text_view_new
|
||||
@@@include
|
||||
tfetextview/tfetextview.c tfe_text_view_new_with_file tfe_text_view_new
|
||||
@@@
|
||||
|
||||
- 21-24: `tfe_text_view_new` function.
|
||||
Just returns the value from the function `g_object_new` but casts it to the pointer to GtkWidget.
|
||||
|
@ -85,7 +91,9 @@ Then, the function changes `tv->file` and save the contents to the specified fil
|
|||
If an error occurs, it is shown to the user through the message dialog.
|
||||
The error is managed only in the TfeTextView instance and no information is notified to the caller.
|
||||
|
||||
@@@ tfetextview/tfetextview.c saveas_dialog_response tfe_text_view_save tfe_text_view_saveas
|
||||
@@@include
|
||||
tfetextview/tfetextview.c saveas_dialog_response tfe_text_view_save tfe_text_view_saveas
|
||||
@@@
|
||||
|
||||
- 20-56: `Tfe_text_view_save` function.
|
||||
- 22: If `tv` is not a pointer to TfeTextView, then it logs an error message and immediately returns.
|
||||
|
@ -148,7 +156,9 @@ However, even if the buffer is not empty, `tfe_text_view_open` doesn't treat it
|
|||
If you want to revert the buffer, calling this function is appropriate.
|
||||
Otherwise probably bad things will happen.
|
||||
|
||||
@@@ tfetextview/tfetextview.c open_dialog_response tfe_text_view_open
|
||||
@@@include
|
||||
tfetextview/tfetextview.c open_dialog_response tfe_text_view_open
|
||||
@@@
|
||||
|
||||
- 37-50: `tfe_text_view_open` function.
|
||||
- 44-47: Generates GtkFileChooserDialog.
|
||||
|
@ -188,7 +198,9 @@ However, in Gtk4, `gtk_dialog_run`is unavailable any more.
|
|||
|
||||
`gtk_text_view_get_file` is a simple function show as follows.
|
||||
|
||||
@@@ tfetextview/tfetextview.c tfe_text_view_get_file
|
||||
@@@include
|
||||
tfetextview/tfetextview.c tfe_text_view_get_file
|
||||
@@@
|
||||
|
||||
The important thing is to duplicate `tv->file`.
|
||||
Otherwise, if the caller frees the GFile object, `tv->file` is no more guaranteed to point the GFile.
|
||||
|
|
|
@ -6,7 +6,9 @@ A set of functions related to GtkNotebook are declared in `tfenotebook.h`.
|
|||
The word "tfenotebook" is used only in filenames.
|
||||
There's no "TfeNotebook" object.
|
||||
|
||||
@@@ tfe5/tfenotebook.h
|
||||
@@@include
|
||||
tfe5/tfenotebook.h
|
||||
@@@
|
||||
|
||||
This header file describes the public functions in `tfenotebook.c`.
|
||||
|
||||
|
@ -33,7 +35,9 @@ Now let's look at each program of the functions.
|
|||
|
||||
## notebook\_page\_new
|
||||
|
||||
@@@ tfe5/tfenotebook.c get_untitled notebook_page_build notebook_page_new
|
||||
@@@include
|
||||
tfe5/tfenotebook.c get_untitled notebook_page_build notebook_page_new
|
||||
@@@
|
||||
|
||||
- 28-38: `notebook_page_new` function.
|
||||
- 30: `g_return_if_fail` is used to check the argument.
|
||||
|
@ -60,7 +64,9 @@ In that case, use g\_object\_set to set the property.
|
|||
|
||||
## notebook\_page\_new\_with\_file
|
||||
|
||||
@@@ tfe5/tfenotebook.c notebook_page_new_with_file
|
||||
@@@include
|
||||
tfe5/tfenotebook.c notebook_page_new_with_file
|
||||
@@@
|
||||
|
||||
- 9-10: Calls `tfe_text_view_new_with_file`.
|
||||
If the function returns NULL, then it does nothing and returns.
|
||||
|
@ -69,7 +75,9 @@ The return value NULL means that an error has happened.
|
|||
|
||||
## notebook\_page\_open
|
||||
|
||||
@@@ tfe5/tfenotebook.c open_response notebook_page_open
|
||||
@@@include
|
||||
tfe5/tfenotebook.c open_response notebook_page_open
|
||||
@@@
|
||||
|
||||
- 19-28: `notebook_page_open` function.
|
||||
- 25: Generates TfeTextView object.
|
||||
|
@ -91,7 +99,9 @@ Gets the filename, builds the contents of the page.
|
|||
|
||||
## notebook\_page\_save
|
||||
|
||||
@@@ tfe5/tfenotebook.c notebook_page_save
|
||||
@@@include
|
||||
tfe5/tfenotebook.c notebook_page_save
|
||||
@@@
|
||||
|
||||
- 7-9: Get TfeTextView belongs to the current notebook page.
|
||||
- 10: Call `tfe_text_view_save`.
|
||||
|
@ -102,7 +112,9 @@ The function `file_changed` is a handler connected to "change-file" signal.
|
|||
If the file in TfeTextView is changed, it emits this signal.
|
||||
This handler changes the label of GtkNotebookPage.
|
||||
|
||||
@@@ tfe5/tfenotebook.c file_changed
|
||||
@@@include
|
||||
tfe5/tfenotebook.c file_changed
|
||||
@@@
|
||||
|
||||
- 8: Gets GFile from TfeTextView.
|
||||
- 9: Gets GkScrolledWindow which is the parent widget of `tv`.
|
||||
|
|
|
@ -13,7 +13,9 @@ It does following things.
|
|||
Th function `main` is the first invoked function in C language.
|
||||
It connects the command line given by the user and GTK application.
|
||||
|
||||
@@@ tfe5/tfeapplication.c main
|
||||
@@@include
|
||||
tfe5/tfeapplication.c main
|
||||
@@@
|
||||
|
||||
- 6: Generates GtkApplication object.
|
||||
- 8-10: Connects "startup", "activate" and "open signals to their handlers.
|
||||
|
@ -31,7 +33,9 @@ What the signal handler needs to do is initialization of the application.
|
|||
|
||||
The handler is as follows.
|
||||
|
||||
@@@ tfe5/tfeapplication.c tfe_startup
|
||||
@@@include
|
||||
tfe5/tfeapplication.c tfe_startup
|
||||
@@@
|
||||
|
||||
- 12-15: Builds widgets using ui file (resource).
|
||||
Connects the top window and the application using `gtk_window_set_application`.
|
||||
|
@ -129,7 +133,9 @@ CSS in the context takes precedence over CSS in the display.
|
|||
The handler of "activate" and "open" signal are `tfe_activate` and `tfe_open` respectively.
|
||||
They just generate a new GtkNotebookPage.
|
||||
|
||||
@@@ tfe5/tfeapplication.c tfe_activate tfe_open
|
||||
@@@include
|
||||
tfe5/tfeapplication.c tfe_activate tfe_open
|
||||
@@@
|
||||
|
||||
- 1-14: `tfe_activate`.
|
||||
- 8-10: Gets GtkNotebook object.
|
||||
|
@ -178,7 +184,9 @@ The second instance immediately quits so shell prompt soon appears.
|
|||
|
||||
## a series of handlers correspond to the button signals
|
||||
|
||||
@@@ tfe5/tfeapplication.c open_clicked new_clicked save_clicked close_clicked
|
||||
@@@include
|
||||
tfe5/tfeapplication.c open_clicked new_clicked save_clicked close_clicked
|
||||
@@@
|
||||
|
||||
`open_clicked`, `new_clicked` and `save_clicked` just call corresponding notebook page functions.
|
||||
`close_clicked` is a bit complicated.
|
||||
|
@ -189,7 +197,9 @@ First, get the top level window and call `gtk_window_destroy`.
|
|||
|
||||
## meson.build
|
||||
|
||||
@@@ tfe5/meson.build
|
||||
@@@include
|
||||
tfe5/meson.build
|
||||
@@@
|
||||
|
||||
In this file, just the source file names are modified.
|
||||
|
||||
|
|
|
@ -31,43 +31,61 @@ It is a good practice for you to add more features.
|
|||
|
||||
## meson.build
|
||||
|
||||
@@@ tfe5/meson.build
|
||||
@@@include
|
||||
tfe5/meson.build
|
||||
@@@
|
||||
|
||||
## tfe.gresource.xml
|
||||
|
||||
@@@ tfe5/tfe.gresource.xml
|
||||
@@@include
|
||||
tfe5/tfe.gresource.xml
|
||||
@@@
|
||||
|
||||
## tfe.ui
|
||||
|
||||
@@@ tfe5/tfe.ui
|
||||
@@@include
|
||||
tfe5/tfe.ui
|
||||
@@@
|
||||
|
||||
## tfe.h
|
||||
|
||||
@@@ tfe5/tfe.h
|
||||
@@@include
|
||||
tfe5/tfe.h
|
||||
@@@
|
||||
|
||||
## tfeapplication.c
|
||||
|
||||
@@@ tfe5/tfeapplication.c
|
||||
@@@include
|
||||
tfe5/tfeapplication.c
|
||||
@@@
|
||||
|
||||
## tfenotebook.h
|
||||
|
||||
@@@ tfe5/tfenotebook.h
|
||||
@@@include
|
||||
tfe5/tfenotebook.h
|
||||
@@@
|
||||
|
||||
## tfenotebook.c
|
||||
|
||||
@@@ tfe5/tfenotebook.c
|
||||
@@@include
|
||||
tfe5/tfenotebook.c
|
||||
@@@
|
||||
|
||||
## tfetextview.h
|
||||
|
||||
@@@ tfetextview/tfetextview.h
|
||||
@@@include
|
||||
tfetextview/tfetextview.h
|
||||
@@@
|
||||
|
||||
## tfetextview.c
|
||||
|
||||
@@@ tfetextview/tfetextview.c
|
||||
@@@include
|
||||
tfetextview/tfetextview.c
|
||||
@@@
|
||||
|
||||
## Total number of lines, words and characters
|
||||
|
||||
$$$
|
||||
@@@shell
|
||||
LANG=C wc tfe5/meson.build tfe5/tfeapplication.c tfe5/tfe.gresource.xml tfe5/tfe.h tfe5/tfenotebook.c tfe5/tfenotebook.h tfetextview/tfetextview.c tfetextview/tfetextview.h tfe5/tfe.ui
|
||||
$$$
|
||||
@@@
|
||||
|
||||
|
|
|
@ -117,7 +117,9 @@ So, if the action is activated, the handler will be invoked.
|
|||
|
||||
The following is a simple example of menus and actions.
|
||||
|
||||
@@@ menu/menu1.c
|
||||
@@@include
|
||||
menu/menu1.c
|
||||
@@@
|
||||
|
||||
- 3-7: `quit_activated` is a handler of an action `act_quit`.
|
||||
Handlers of actions have three parameters.
|
||||
|
|
|
@ -204,7 +204,9 @@ When GVariantType is generated, the type is expressed by the string.
|
|||
The following program is a simple example.
|
||||
It finally output the string "s".
|
||||
|
||||
@@@ menu/gvarianttype_test.c
|
||||
@@@include
|
||||
menu/gvarianttype_test.c
|
||||
@@@
|
||||
|
||||
- `g_variant_tpe_new` generates GVariantType.
|
||||
It uses a type string "s" which means string.
|
||||
|
@ -227,7 +229,9 @@ And the radio button of the selected menu turns on.
|
|||
|
||||
The code is as follows.
|
||||
|
||||
@@@ menu/menu2.c
|
||||
@@@include
|
||||
menu/menu2.c
|
||||
@@@
|
||||
|
||||
- 5-26: Signal handlers.
|
||||
They have been explained in this section.
|
||||
|
|
|
@ -67,11 +67,15 @@ Its name is `menu3`.
|
|||
|
||||
The following is the ui file of the menu in `menu3`.
|
||||
|
||||
@@@ menu3/menu3.ui
|
||||
@@@include
|
||||
menu3/menu3.ui
|
||||
@@@
|
||||
|
||||
The ui file is converted to the resource by the resource compiler `glib-compile-resouces` with xml file below.
|
||||
|
||||
@@@ menu3/menu3.gresource.xml
|
||||
@@@include
|
||||
menu3/menu3.gresource.xml
|
||||
@@@
|
||||
|
||||
GtkBuilder builds menus from the resource.
|
||||
|
||||
|
@ -160,9 +164,13 @@ The code above does:
|
|||
|
||||
The C source code of `menu3` and `meson.build` is as follows.
|
||||
|
||||
@@@ menu3/menu3.c
|
||||
@@@include
|
||||
menu3/menu3.c
|
||||
@@@
|
||||
|
||||
meson.build
|
||||
|
||||
@@@ menu3/meson.build
|
||||
@@@include
|
||||
menu3/meson.build
|
||||
@@@
|
||||
|
||||
|
|
|
@ -44,7 +44,9 @@ This will be a destination.
|
|||
|
||||
Here's a simple example code that draws a small square and save it as a png file.
|
||||
|
||||
@@@ misc/cairo.c
|
||||
@@@include
|
||||
misc/cairo.c
|
||||
@@@
|
||||
|
||||
- 1: Includes the header file of cairo.
|
||||
- 12: `cairo_image_surface_create` creates an image surface.
|
||||
|
@ -85,7 +87,9 @@ If you aren't familiar with cairo, it is strongly recommended to read the [tutor
|
|||
|
||||
The following is a very simple example.
|
||||
|
||||
@@@ misc/da1.c
|
||||
@@@include
|
||||
misc/da1.c
|
||||
@@@
|
||||
|
||||
The function `main` is almost same as before.
|
||||
The two functions `on_activate` and `draw_function` is important in this example.
|
||||
|
|
|
@ -32,7 +32,9 @@ The image in the previous subsection gives us the structure of the widgets.
|
|||
Title bar, four buttons in the tool bar and two widgets textview and drawing area.
|
||||
The ui file is as follows.
|
||||
|
||||
@@@ color/color.ui
|
||||
@@@include
|
||||
color/color.ui
|
||||
@@@
|
||||
|
||||
- 9-53: This part describes the tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
|
||||
This is similar to the toolbar of tfe text editor in [Section 8](sec8.src.md).
|
||||
|
@ -50,14 +52,18 @@ TfeTextView is a child of GtkScrolledWindow.
|
|||
The xml file for the resource compiler is almost same as before.
|
||||
Just substitute "color" for "tfe".
|
||||
|
||||
@@@ color/color.gresource.xml
|
||||
@@@include
|
||||
color/color.gresource.xml
|
||||
@@@
|
||||
|
||||
## Tfetextview.h, tfetextview.c and color.h
|
||||
|
||||
First two files are the same as before.
|
||||
Color.h just includes tfetextview.h.
|
||||
|
||||
@@@ color/color.h
|
||||
@@@include
|
||||
color/color.h
|
||||
@@@
|
||||
|
||||
## Colorapplication.c
|
||||
|
||||
|
@ -72,7 +78,9 @@ Particularly, `Run` signal handler is the point in this program.
|
|||
|
||||
The following is `colorapplication.c`.
|
||||
|
||||
@@@ color/colorapplication.c
|
||||
@@@include
|
||||
color/colorapplication.c
|
||||
@@@
|
||||
|
||||
- 108-121: The function `main` is almost same as before but there are some differences.
|
||||
The application ID is "com.github.ToshioCP.color".
|
||||
|
@ -114,7 +122,9 @@ Alpha channel is used.
|
|||
This file is almost same as before.
|
||||
An argument "export_dynamic: true" is added to executable function.
|
||||
|
||||
@@@ color/meson.build
|
||||
@@@include
|
||||
color/meson.build
|
||||
@@@
|
||||
|
||||
## Compile and execute it
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@ That's all.
|
|||
Very simple.
|
||||
The following is the C code representing the scenario above.
|
||||
|
||||
@@@ misc/pr1.c
|
||||
@@@include
|
||||
misc/pr1.c
|
||||
@@@
|
||||
|
||||
The first line says that this program includes the header files of the Gtk libraries.
|
||||
The function `main` above is a startup function in C language.
|
||||
|
@ -85,7 +87,9 @@ Now we can solve the problem in `pr1.c`.
|
|||
We need to connect the activate signal to a handler.
|
||||
We use a function `g_signal_connect` which connects a signal to a handler.
|
||||
|
||||
@@@ misc/pr2.c
|
||||
@@@include
|
||||
misc/pr2.c
|
||||
@@@
|
||||
|
||||
First, we define the handler `on_activate` which simply displays a message.
|
||||
In the function `main`, we add `g_signal_connect` before `g_application_run`.
|
||||
|
@ -155,7 +159,9 @@ Now rewrite the function `on_activate`.
|
|||
|
||||
#### Generate a GtkWindow
|
||||
|
||||
@@@ misc/pr3.c on_activate
|
||||
@@@include
|
||||
misc/pr3.c on_activate
|
||||
@@@
|
||||
|
||||
Widget is an abstract concept that includes all the GUI interfaces such as windows, dialogs, buttons, multi-line text, containers and so on.
|
||||
And GtkWidget is a base object from which all the GUI objects derive.
|
||||
|
@ -236,7 +242,9 @@ It is recommended to use it instead of GtkWindow when you use GtkApplication.
|
|||
|
||||
Now rewrite the program and use GtkAppliction Window.
|
||||
|
||||
@@@ misc/pr4.c on_activate
|
||||
@@@include
|
||||
misc/pr4.c on_activate
|
||||
@@@
|
||||
|
||||
When you generate GtkApplicationWindow, you need to give GtkApplication object as an argument.
|
||||
Then it automatically connect these two objects.
|
||||
|
|
|
@ -9,7 +9,9 @@ Now we go on to the next topic, widgets in the window.
|
|||
The simplest widget is GtkLabel.
|
||||
It is a widget with a string in it.
|
||||
|
||||
@@@ misc/lb1.c
|
||||
@@@include
|
||||
misc/lb1.c
|
||||
@@@
|
||||
|
||||
Save this program to a file `lb1.c`.
|
||||
Then compile and run it.
|
||||
|
@ -24,9 +26,9 @@ A window with a message "Hello." appears.
|
|||
There's only a little change between `pr4.c` and `lb1.c`.
|
||||
Diff is a good program to know the difference between two files.
|
||||
|
||||
$$$
|
||||
@@@shell
|
||||
cd misc; diff pr4.c lb1.c
|
||||
$$$
|
||||
@@@
|
||||
|
||||
This tells us:
|
||||
|
||||
|
@ -57,7 +59,9 @@ In this subsection, we will make a button with a label.
|
|||
When a button is clicked on, it emits a "clicked" signal.
|
||||
The following program shows how to catch the signal and do something.
|
||||
|
||||
@@@ misc/lb2.c
|
||||
@@@include
|
||||
misc/lb2.c
|
||||
@@@
|
||||
|
||||
Look at the line 17 to 19.
|
||||
First, it generates a GtkButton widget `btn` with a label "Click me".
|
||||
|
@ -80,13 +84,15 @@ However, using g_print is out of harmony with GTK which is a GUI library.
|
|||
So, we will change the handler.
|
||||
The following code is `lb3.c`.
|
||||
|
||||
@@@ misc/lb3.c click_cb on_activate
|
||||
@@@include
|
||||
misc/lb3.c click_cb on_activate
|
||||
@@@
|
||||
|
||||
And the difference between `lb2.c` and `lb3.c` is as follows.
|
||||
|
||||
$$$
|
||||
@@@shell
|
||||
cd misc; diff lb2.c lb3.c
|
||||
$$$
|
||||
@@@
|
||||
|
||||
The change is:
|
||||
|
||||
|
@ -119,7 +125,9 @@ After this, the Widgets are connected as following diagram.
|
|||
|
||||
Now, code it.
|
||||
|
||||
@@@ misc/lb4.c
|
||||
@@@include
|
||||
misc/lb4.c
|
||||
@@@
|
||||
|
||||
Look at the function `on_activate`.
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@ GtkTextview is a widget for multi-line text editing.
|
|||
GtkTextBuffer is a text buffer which is connected to GtkTextView.
|
||||
See a sample program `tfv1.c` below.
|
||||
|
||||
@@@ tfv/tfv1.c
|
||||
@@@include
|
||||
tfv/tfv1.c
|
||||
@@@
|
||||
|
||||
Look at line 25.
|
||||
GtkTextView is generated and its pointer is assigned to `tv`.
|
||||
|
@ -43,13 +45,15 @@ What we need to do is:
|
|||
Modify `tfv1.c` and save it as `tfv2.c`.
|
||||
The difference between these two files is very little.
|
||||
|
||||
$$$
|
||||
@@@shell
|
||||
cd tfv; diff tfv1.c tfv2.c
|
||||
$$$
|
||||
@@@
|
||||
|
||||
Though you can modify the source file by this diff output, It's good for you to show `tfv2.c`.
|
||||
|
||||
@@@ tfv/tfv2.c
|
||||
@@@include
|
||||
tfv/tfv2.c
|
||||
@@@
|
||||
|
||||
Now compile and run it.
|
||||
This time the window doesn't extend even if you type a lot of characters.
|
||||
|
|
|
@ -95,7 +95,9 @@ It works as follows.
|
|||
|
||||
The program is as follows.
|
||||
|
||||
@@@ tfv/tfv3.c
|
||||
@@@include
|
||||
tfv/tfv3.c
|
||||
@@@
|
||||
|
||||
Save it as `tfv3.c`.
|
||||
Then compile and run it.
|
||||
|
@ -164,7 +166,9 @@ It is shown in the right screenshot.
|
|||
GtkNotebook widget is between GtkApplicationWindow and GtkScrolledWindow.
|
||||
Now I want to show you the program `tfv4.c`.
|
||||
|
||||
@@@ tfv/tfv4.c
|
||||
@@@include
|
||||
tfv/tfv4.c
|
||||
@@@
|
||||
|
||||
Most of the change is in the function `on_open`.
|
||||
The numbers at the left of the following items are line numbers in the source code.
|
||||
|
|
|
@ -167,7 +167,9 @@ The argument `win` is GtkApplicationWindow, in which the signal "close-request"
|
|||
`G_CALLBACK` cast is necessary for the handler.
|
||||
The program of `before_close` is as follows.
|
||||
|
||||
@@@ tfe/tfe1.c before_close
|
||||
@@@include
|
||||
tfe/tfe1.c before_close
|
||||
@@@
|
||||
|
||||
The numbers on the left of items are line numbers in the source code.
|
||||
|
||||
|
@ -184,7 +186,9 @@ Just remember these lines for the present.
|
|||
|
||||
Now I will show you all the source code of `tfe1`.c.
|
||||
|
||||
@@@ tfe/tfe1.c
|
||||
@@@include
|
||||
tfe/tfe1.c
|
||||
@@@
|
||||
|
||||
- 102: Sets the pointer to GFile into TfeTextView.
|
||||
`files[i]` is a pointer to GFile structure.
|
||||
|
|
|
@ -14,7 +14,9 @@ Signals and handlers will be explained later.
|
|||
The screenshot above shows the layout.
|
||||
The function `on_open` in the source code `tfe2.c` is as follows.
|
||||
|
||||
@@@ tfe/tfe2.c on_open
|
||||
@@@include
|
||||
tfe/tfe2.c on_open
|
||||
@@@
|
||||
|
||||
The point is how to build the window.
|
||||
|
||||
|
@ -48,7 +50,9 @@ It reduces the cumbersome work.
|
|||
|
||||
First, let's look at the ui file `tfe3.ui` that defines a structure of the widgets.
|
||||
|
||||
@@@ tfe/tfe3.ui
|
||||
@@@include
|
||||
tfe/tfe3.ui
|
||||
@@@
|
||||
|
||||
This is coded with XML structure.
|
||||
Constructs beginning with `<` and ending with `>` are called tags.
|
||||
|
@ -87,9 +91,9 @@ All the widgets are connected based on the parent-children relationship describe
|
|||
We only need `win` and `nb` for the program after this, so we don't need to take out any other widgets.
|
||||
This reduces lines in the C source file.
|
||||
|
||||
$$$
|
||||
@@@shell
|
||||
cd tfe; diff tfe2.c tfe3.c
|
||||
$$$
|
||||
@@@
|
||||
|
||||
`60,103c61,65` means 42 (=103-60+1) lines change to 5 (=65-61+1) lines.
|
||||
Therefore 37 lines are reduced.
|
||||
|
@ -97,7 +101,9 @@ Using ui file not only shortens C source files, but also makes the widgets' stru
|
|||
|
||||
Now I'll show you `on_open` function in the C source code `tfe3.c`.
|
||||
|
||||
@@@ tfe/tfe3.c on_open
|
||||
@@@include
|
||||
tfe/tfe3.c on_open
|
||||
@@@
|
||||
|
||||
The whole source code of `tfe3.c` is stored in [src/tfe](https://github.com/ToshioCP/Gtk4-tutorial/tree/main/src/tfe) directory.
|
||||
If you want to see it, click the link above.
|
||||
|
@ -147,7 +153,9 @@ And after compilation, it bundles them up into one Gresource object.
|
|||
An xml file is necessary for the resource compiler `glib-compile-resources`.
|
||||
It describes resource files.
|
||||
|
||||
@@@ tfe/tfe3.gresource.xml
|
||||
@@@include
|
||||
tfe/tfe3.gresource.xml
|
||||
@@@
|
||||
|
||||
- 2: `gresources` tag can include multiple gresources (gresource tags).
|
||||
However, this xml has only one gresource.
|
||||
|
@ -159,9 +167,9 @@ If you want to add more files, then insert them between line 4 and 5.
|
|||
Save this xml text to `tfe3.gresource.xml`.
|
||||
The gresource compiler `glib-compile-resources` shows its usage with the argument `--help`.
|
||||
|
||||
$$$
|
||||
@@@shell
|
||||
LANG=C glib-compile-resources --help
|
||||
$$$
|
||||
@@@
|
||||
|
||||
Now run the compiler.
|
||||
|
||||
|
|
|
@ -40,23 +40,33 @@ All the source files are listed below.
|
|||
|
||||
`tfetextview.h`
|
||||
|
||||
@@@ tfe4/tfetextview.h
|
||||
@@@include
|
||||
tfe4/tfetextview.h
|
||||
@@@
|
||||
|
||||
`tfetextview.c`
|
||||
|
||||
@@@ tfe4/tfetextview.c
|
||||
@@@include
|
||||
tfe4/tfetextview.c
|
||||
@@@
|
||||
|
||||
`tfe.c`
|
||||
|
||||
@@@ tfe4/tfe.c
|
||||
@@@include
|
||||
tfe4/tfe.c
|
||||
@@@
|
||||
|
||||
`tfe.ui`
|
||||
|
||||
@@@ tfe4/tfe.ui
|
||||
@@@include
|
||||
tfe4/tfe.ui
|
||||
@@@
|
||||
|
||||
`tfe.gresource.xml`
|
||||
|
||||
@@@ tfe4/tfe.gresource.xml
|
||||
@@@include
|
||||
tfe4/tfe.gresource.xml
|
||||
@@@
|
||||
|
||||
## Make
|
||||
|
||||
|
@ -100,7 +110,9 @@ If the modification time of `sample.c` is older then the generation of `sample.o
|
|||
|
||||
The Makefile for `tfe` is as follows.
|
||||
|
||||
@@@ tfe4/Makefile
|
||||
@@@include
|
||||
tfe4/Makefile
|
||||
@@@
|
||||
|
||||
You only need to type `make`.
|
||||
|
||||
|
@ -128,7 +140,9 @@ However, Ruby is really sophisticated and recommendable script language.
|
|||
|
||||
Rake has task and file task, which is similar to target, prerequisite and recipe in make.
|
||||
|
||||
@@@ tfe4/Rakefile
|
||||
@@@include
|
||||
tfe4/Rakefile
|
||||
@@@
|
||||
|
||||
What `Rakefile` describes is almost same as `Makefile` in the previous subsection.
|
||||
|
||||
|
@ -160,7 +174,9 @@ Many developers are using meson and ninja now.
|
|||
|
||||
To use meson, you first need to write `meson.build` file.
|
||||
|
||||
@@@ tfe4/meson.build
|
||||
@@@include
|
||||
tfe4/meson.build
|
||||
@@@
|
||||
|
||||
- 1: The function `project` defines things about the project.
|
||||
The first parameter is the name of the project and the second is the programming language.
|
||||
|
|
139
test/test_lib_sec_file.rb
Normal file
139
test/test_lib_sec_file.rb
Normal file
|
@ -0,0 +1,139 @@
|
|||
# test_lib_sec_file.rb
|
||||
require_relative "../lib/lib_sec_file.rb"
|
||||
|
||||
# Sample files for the test
|
||||
sample_c = <<'EOS'
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
printf ("Hello world.\n");
|
||||
}
|
||||
EOS
|
||||
|
||||
sec1_text = <<'EOS'
|
||||
This is a test file.
|
||||
The sorce of `sample.c` is:
|
||||
|
||||
@@@include
|
||||
sample.c main
|
||||
@@@
|
||||
|
||||
It is the simplest C program.
|
||||
EOS
|
||||
|
||||
sec2_text = <<'EOS'
|
||||
To compile the C source file `sample.c`, type:
|
||||
|
||||
~~~
|
||||
$ gcc sample.c
|
||||
~~~
|
||||
|
||||
Then executable file `a.out` is generated.
|
||||
|
||||
@@@shell
|
||||
ls
|
||||
@@@
|
||||
|
||||
To execute it, type:
|
||||
|
||||
~~~
|
||||
$ ./a.out
|
||||
~~~
|
||||
|
||||
The source code is in [Section 1](sec1.src.md)
|
||||
EOS
|
||||
|
||||
sec05_text = <<'EOS'
|
||||
Prerequisite
|
||||
|
||||
- Linux OS like Ubuntu or Debian.
|
||||
- gcc
|
||||
EOS
|
||||
|
||||
files = [
|
||||
["temp/sample.c", sample_c],
|
||||
["temp/sec1.src.md", sec1_text],
|
||||
["temp/sec2.src.md", sec2_text],
|
||||
["temp/sec0.5.src.md", sec05_text]
|
||||
]
|
||||
|
||||
# Generate sample file
|
||||
unless Dir.exist? "temp"
|
||||
Dir.mkdir "temp"
|
||||
end
|
||||
files.each do |f|
|
||||
File.write f[0], f[1]
|
||||
end
|
||||
|
||||
# Test Sec_file
|
||||
print "****** Sec_file class test ******\n"
|
||||
src_sec05 = Sec_file.new "temp/sec0.5.src.md"
|
||||
src_sec1 = Sec_file.new "temp/sec1.src.md"
|
||||
src_sec2 = Sec_file.new "temp/sec2.src.md"
|
||||
test_items = [
|
||||
["path", "\"temp/sec1.src.md\""],
|
||||
["basename", "\"sec1.src.md\""],
|
||||
["dirname", "\"temp\""],
|
||||
["c_files", "[ \"temp/sample.c\" ]"],
|
||||
["to_md", "\"sec1.md\""],
|
||||
["to_html", "\"sec1.html\""],
|
||||
["to_tex", "\"sec1.tex\""],
|
||||
["num", "\"1\""],
|
||||
["to_f", "1.0"],
|
||||
["<=> src_sec05", "1"],
|
||||
["<=> src_sec1", "0"],
|
||||
["<=> src_sec2", "-1"],
|
||||
["is_i?", "true"]
|
||||
]
|
||||
test_items.each do |item|
|
||||
if eval("src_sec1.#{item[0]} != #{item[1]}")
|
||||
print "src_sec1.#{item[0]} != #{item[1]}\n"
|
||||
print " .... src_sec1.#{item[0]} is #{eval("src_sec1.#{item[0]}")}\n"
|
||||
end
|
||||
end
|
||||
if src_sec05.is_i? != false
|
||||
print "src_sec05.is_i? != false\n"
|
||||
end
|
||||
src_sec2.renum! 3
|
||||
print "\n\"src_sec2.renum! 3\" is invoked.\n\n"
|
||||
if src_sec2.path != "temp/sec3.src.md"
|
||||
print "temp/sec2.src.md is renumbered to 3, but the name didn't changed to sec3.src.md\n"
|
||||
print " .... The name is #{src_sec2.path})}\n"
|
||||
end
|
||||
unless File.exist? "temp/sec3.src.md"
|
||||
print "temp/sec3/src/md doesn't exist.\n"
|
||||
end
|
||||
if src_sec2.basename != "sec3.src.md"
|
||||
print "The new basename isn't sec3.src.md.\n"
|
||||
print " .... It is #{src_sec2.basename}.\n"
|
||||
end
|
||||
if src_sec2.dirname != "temp"
|
||||
print "The new dirname isn't temp.\n"
|
||||
print " .... It is #{src_sec2.dirname}.\n"
|
||||
end
|
||||
|
||||
# Test Sec_files
|
||||
print "****** Sec_files class test ******\n"
|
||||
sec_files = Sec_files.new [src_sec05, src_sec1, src_sec2]
|
||||
sec_files.renum!
|
||||
print "\n\"sec_files.renum!\" is invoked.\n\n"
|
||||
filenames = sec_files.map { |sec_file| sec_file.path }
|
||||
if filenames != ["temp/sec1.src.md", "temp/sec2.src.md", "temp/sec3.src.md"]
|
||||
print "Renumbering failed.\n"
|
||||
print "The filenames are:\n"
|
||||
p filenames
|
||||
end
|
||||
s_line = /The source code is in \[Section \d\]\(sec\d.src.md\)/
|
||||
buf = File.readlines src_sec2.path
|
||||
i = buf.find_index {|l| l =~ s_line }
|
||||
if i
|
||||
line = buf[i]
|
||||
else
|
||||
print "The line \"The source code is in [Section \\d](sec\\d.src.md)\" didn't find in src_sec2.\n"
|
||||
end
|
||||
if line != "The source code is in [Section 2](sec2.src.md)\n"
|
||||
print "\"Section 1\" didn't change to \"Section 2\", or \"sec1\" didn't change to \"sec2\".\n"
|
||||
print " .... The line is #{line.chomp}.\n"
|
||||
end
|
||||
system "rm", "-rf", "temp"
|
341
test/test_lib_src2md.rb
Normal file
341
test/test_lib_src2md.rb
Normal file
|
@ -0,0 +1,341 @@
|
|||
# test_lib_src2md.rb
|
||||
require_relative '../lib/lib_src2md.rb'
|
||||
|
||||
# Many kinds of file types are supported.
|
||||
# .c => C, .h => C, .rb => ruby, Rakefile, => ruby, .xml => xml, .ui => xml, .y => bison, .lex => lex, .build => meson, .md => markdown, Makefile => makefile
|
||||
|
||||
sample_c = <<'EOS'
|
||||
/* This comment is very long, longer than 100. It must be folded if this file is converted to latex. Because latex doesn't care about verbatim lines. The lines are printed as they are. */
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
printf_something (char *something) {
|
||||
printf ("%s\n", something);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
printf_something ("Hello world.");
|
||||
}
|
||||
EOS
|
||||
|
||||
sample_h = <<'EOS'
|
||||
#include <gtk/gtk.h>
|
||||
EOS
|
||||
|
||||
sample_rb = <<'EOS'
|
||||
print "Hello ruby.\n"
|
||||
EOS
|
||||
|
||||
rakefile = <<'EOS'
|
||||
task default: "a.out"
|
||||
file "a.out" => "sample.c" do
|
||||
sh "gcc sample.c"
|
||||
end
|
||||
EOS
|
||||
|
||||
sample_xml = <<'EOS'
|
||||
<div class="h1" color="red">Fatal error!!</div>
|
||||
EOS
|
||||
|
||||
sample_ui = <<'EOS'
|
||||
<object class="GtkWindow" id="win"></object>
|
||||
EOS
|
||||
|
||||
sample_y = <<'EOS'
|
||||
program: statement | program statement ;
|
||||
EOS
|
||||
|
||||
sample_lex = <<'EOS'
|
||||
[a-zA-Z0-9] return ALNUM;
|
||||
EOS
|
||||
|
||||
sample_build = <<'EOS'
|
||||
project('sampe', 'c')
|
||||
EOS
|
||||
|
||||
sample0_md = <<'EOS'
|
||||
# Sample text in maridown language
|
||||
EOS
|
||||
|
||||
makefile = <<'EOS'
|
||||
a.out: sample.c
|
||||
cc sample.c
|
||||
EOS
|
||||
|
||||
sample_src_md = <<'EOS'
|
||||
# Sample.src.md
|
||||
|
||||
This .src.md file is made for the test for lib_src2md.rb.
|
||||
|
||||
Sample.c with line number is:
|
||||
|
||||
@@@include
|
||||
sample.c
|
||||
@@@
|
||||
|
||||
The following is also Sample.c with line number.
|
||||
|
||||
@@@include -n
|
||||
sample.c
|
||||
@@@
|
||||
|
||||
The following is Sample.c without line number.
|
||||
|
||||
@@@include -N
|
||||
sample.c
|
||||
@@@
|
||||
|
||||
The following prints only `printf_something`.
|
||||
|
||||
@@@include
|
||||
sample.c printf_something
|
||||
@@@
|
||||
|
||||
The following prints `printf_something` and `main`.
|
||||
|
||||
@@@include
|
||||
sample.c printf_something main
|
||||
@@@
|
||||
|
||||
Check info string.
|
||||
|
||||
@@@include
|
||||
sample.c
|
||||
sample.h
|
||||
sample.rb
|
||||
Rakefile
|
||||
sample.xml
|
||||
sample.ui
|
||||
sample.y
|
||||
sample.lex
|
||||
sample.build
|
||||
sample0.md
|
||||
@@@
|
||||
|
||||
Compile sample.c with rake like this:
|
||||
|
||||
@@@shell
|
||||
rake
|
||||
@@@
|
||||
|
||||
@@@shell
|
||||
echo "This text is very long, longer than 100. It must be folded if this file is converted to latex. Because latex doesn't care about verbatim lines. The lines are printed as they are."
|
||||
@@@
|
||||
|
||||
The target type is:
|
||||
|
||||
@@@if gfm
|
||||
gfm
|
||||
@@@elif html
|
||||
html
|
||||
@@@elif latex
|
||||
latex
|
||||
@@@end
|
||||
|
||||
[Relative link](sample.c) will be converted when the target type is gfm or html.
|
||||
Otherwise (latex) the link will be removed.
|
||||
|
||||
Another [relative link](../../Rakefile).
|
||||
|
||||
[Absolute link](https://github.com/ToshioCP) is kept as it is.
|
||||
|
||||
Image link.
|
||||
If the target type is gfm or html, the size will be removed.
|
||||
Otherwise (latex) it remains.
|
||||
|
||||
![Screenshot of the box](../../image/screenshot_lb4.png){width=6.3cm height=5.325cm}
|
||||
EOS
|
||||
|
||||
sample_md = <<EOS
|
||||
# Sample.src.md
|
||||
|
||||
This .src.md file is made for the test for lib_src2md.rb.
|
||||
|
||||
Sample.c with line number is:
|
||||
|
||||
~~~C
|
||||
#{i=1;sample_c.lines.each {|line| line.replace(sprintf("%#2d %s", i, line)); i+=1}.join}~~~
|
||||
|
||||
The following is also Sample.c with line number.
|
||||
|
||||
~~~C
|
||||
#{i=1;sample_c.lines.each {|line| line.replace(sprintf("%#2d %s", i, line)); i+=1}.join}~~~
|
||||
|
||||
The following is Sample.c without line number.
|
||||
|
||||
~~~C
|
||||
#{sample_c}~~~
|
||||
|
||||
The following prints only `printf_something`.
|
||||
|
||||
~~~C
|
||||
1 void
|
||||
2 printf_something (char *something) {
|
||||
3 printf ("%s\\n", something);
|
||||
4 }
|
||||
~~~
|
||||
|
||||
The following prints `printf_something` and `main`.
|
||||
|
||||
~~~C
|
||||
1 void
|
||||
2 printf_something (char *something) {
|
||||
3 printf ("%s\\n", something);
|
||||
4 }
|
||||
5
|
||||
6 int
|
||||
7 main (int argc, char **argv) {
|
||||
8 printf_something ("Hello world.");
|
||||
9 }
|
||||
~~~
|
||||
|
||||
Check info string.
|
||||
|
||||
~~~C
|
||||
#{i=1;sample_c.lines.each {|line| line.replace(sprintf("%#2d %s", i, line)); i+=1}.join}~~~
|
||||
~~~C
|
||||
#{i=1;sample_h.lines.each {|line| line.replace(sprintf("%#1d %s", i, line)); i+=1}.join}~~~
|
||||
~~~ruby
|
||||
#{i=1;sample_rb.lines.each {|line| line.replace(sprintf("%#1d %s", i, line)); i+=1}.join}~~~
|
||||
~~~ruby
|
||||
#{i=1;rakefile.lines.each {|line| line.replace(sprintf("%#1d %s", i, line)); i+=1}.join}~~~
|
||||
~~~xml
|
||||
#{i=1;sample_xml.lines.each {|line| line.replace(sprintf("%#1d %s", i, line)); i+=1}.join}~~~
|
||||
~~~xml
|
||||
#{i=1;sample_ui.lines.each {|line| line.replace(sprintf("%#1d %s", i, line)); i+=1}.join}~~~
|
||||
~~~bison
|
||||
#{i=1;sample_y.lines.each {|line| line.replace(sprintf("%#1d %s", i, line)); i+=1}.join}~~~
|
||||
~~~lex
|
||||
#{i=1;sample_lex.lines.each {|line| line.replace(sprintf("%#1d %s", i, line)); i+=1}.join}~~~
|
||||
~~~meson
|
||||
#{i=1;sample_build.lines.each {|line| line.replace(sprintf("%#1d %s", i, line)); i+=1}.join}~~~
|
||||
~~~markdown
|
||||
#{i=1;sample0_md.lines.each {|line| line.replace(sprintf("%#1d %s", i, line)); i+=1}.join}~~~
|
||||
|
||||
Compile sample.c with rake like this:
|
||||
|
||||
~~~
|
||||
$ rake
|
||||
~~~
|
||||
|
||||
~~~
|
||||
$ echo "This text is very long, longer than 100. It must be folded if this file is converted to latex. Because latex doesn't care about verbatim lines. The lines are printed as they are."
|
||||
This text is very long, longer than 100. It must be folded if this file is converted to latex. Because latex doesn't care about verbatim lines. The lines are printed as they are.
|
||||
~~~
|
||||
|
||||
The target type is:
|
||||
|
||||
gfm
|
||||
|
||||
[Relative link](../temp/sample.c) will be converted when the target type is gfm or html.
|
||||
Otherwise (latex) the link will be removed.
|
||||
|
||||
Another [relative link](../../Rakefile).
|
||||
|
||||
[Absolute link](https://github.com/ToshioCP) is kept as it is.
|
||||
|
||||
Image link.
|
||||
If the target type is gfm or html, the size will be removed.
|
||||
Otherwise (latex) it remains.
|
||||
|
||||
![Screenshot of the box](../../image/screenshot_lb4.png){width=6.3cm height=5.325cm}
|
||||
EOS
|
||||
|
||||
# -------------------
|
||||
# Test goes here.
|
||||
# -------------------
|
||||
|
||||
files = [
|
||||
[sample_c, "sample.c", "C"],
|
||||
[sample_h, "sample.h", "C"],
|
||||
[sample_rb, "sample.rb", "ruby"],
|
||||
[rakefile, "Rakefile", "ruby"],
|
||||
[sample_xml, "sample.xml", "xml"],
|
||||
[sample_ui, "sample.ui", "xml"],
|
||||
[sample_y, "sample.y", "bison"],
|
||||
[sample_lex, "sample.lex", "lex"],
|
||||
[sample_build, "sample.build", "meson"],
|
||||
[sample0_md, "sample0.md", "markdown"],
|
||||
[makefile, "Makefile", "makefile"],
|
||||
[sample_src_md, "sample.src.md", nil]
|
||||
]
|
||||
|
||||
Dir.mkdir "temp" unless Dir.exist? "temp"
|
||||
files.each do |f|
|
||||
File.write "temp/#{f[1]}", f[0]
|
||||
end
|
||||
|
||||
# --- test lang
|
||||
files.each do |f|
|
||||
if f[2] && lang("temp/#{f[1]}") != f[2]
|
||||
print " lang(\"temp/#{f[1]}\") != #{f[2]}\n"
|
||||
end
|
||||
end
|
||||
|
||||
# --- test fold
|
||||
s = fold "*"*50+"\n", 7
|
||||
if s != "*******\n"*7+"*\n"
|
||||
print "Fold didn't work. \"*\"*50 was folded with width 7 was:\n"
|
||||
print s
|
||||
end
|
||||
|
||||
# --- test change_rel_link
|
||||
# general relative link
|
||||
s = "[sample.c](temp/sample.c)"
|
||||
t = change_rel_link s, "test", "gfm"
|
||||
if t != "[sample.c](../test/temp/sample.c)"
|
||||
print "Relative link change according to base directory change didn't work.\n"
|
||||
print " Base directory test => gtm\n"
|
||||
print " Original link => #{s}\n"
|
||||
print " Relative link temp/sample.c => #{t}\n"
|
||||
print " ** Correct new link must be [sample.c](../test/temp/sample.c) **\n"
|
||||
end
|
||||
# link to a section
|
||||
# srcdir/secXX.src.md is converted to dstdir/secXX.md.
|
||||
# Therefore, secXX.src.md must be changed tp secXX.md.
|
||||
s = "[Section 3](sec3.src.md)"
|
||||
t = change_rel_link s, "test", "gfm"
|
||||
if t != "[Section 3](sec3.md)"
|
||||
print "Relative link change according to base directory change didn't work.\n"
|
||||
print " Base directory test => gtm\n"
|
||||
print " Original link => #{s}\n"
|
||||
print " Relative link temp/sample.c => #{t}\n"
|
||||
print " ** Correct new link must be [Section 2](sec3) **\n"
|
||||
end
|
||||
|
||||
# --- test src2md
|
||||
dst_dirs = ["gfm", "html", "latex"]
|
||||
dst_dirs.each do |d|
|
||||
Dir.mkdir d unless Dir.exist? d
|
||||
n = d == "latex" ? 86 : -1
|
||||
src2md "temp/sample.src.md", "#{d}/sample.md", n
|
||||
dst_md = File.read "#{d}/sample.md"
|
||||
if d == "gfm"
|
||||
print "Gfm result didn't match !!\n" if dst_md != sample_md.gsub(/!\[Screenshot of the box\]\(\.\.\/\.\.\/image\/screenshot_lb4\.png\){width=6\.3cm height=5\.325cm}/,"![Screenshot of the box](../../image/screenshot_lb4.png)")
|
||||
elsif d == "html"
|
||||
print "Html result didn't match !!\n" if dst_md != sample_md.gsub(/^gfm$/, "html").gsub(/!\[Screenshot of the box\]\(\.\.\/\.\.\/image\/screenshot_lb4\.png\){width=6\.3cm height=5\.325cm}/,"![Screenshot of the box](../../image/screenshot_lb4.png)")
|
||||
elsif d == "latex"
|
||||
sample_md.gsub!(" 1 /* This comment is very long, longer than 100. It must be folded if this file is converted to latex. Because latex doesn't care about verbatim lines. The lines are printed as they are. */", " 1 /* This comment is very long, longer than 100. It must be folded if this file is co\nnverted to latex. Because latex doesn't care about verbatim lines. The lines are print\ned as they are. */")
|
||||
sample_md.gsub!(/^\/\* This comment is very long, longer than 100\. It must be folded if this file is converted to latex\. Because latex doesn't care about verbatim lines\. The lines are printed as they are\. \*\//, "/* This comment is very long, longer than 100. It must be folded if this file is conve\nrted to latex. Because latex doesn't care about verbatim lines. The lines are printed \nas they are. */")
|
||||
sample_md.gsub!(/\$ echo "This text is very long, longer than 100\. It must be folded if this file is converted to latex\. Because latex doesn't care about verbatim lines\. The lines are printed as they are\."/,"$ echo \"This text is very long, longer than 100. It must be folded if this file is con\nverted to latex. Because latex doesn't care about verbatim lines. The lines are printe\nd as they are.\"")
|
||||
sample_md.gsub!(/^This text is very long, longer than 100\. It must be folded if this file is converted to latex\. Because latex doesn't care about verbatim lines\. The lines are printed as they are\./, "This text is very long, longer than 100. It must be folded if this file is converted t\no latex. Because latex doesn't care about verbatim lines. The lines are printed as the\ny are.")
|
||||
sample_md.gsub!(/^gfm/,"latex")
|
||||
sample_md.gsub!(/\[((R|r)elative link)\]\([^)]+\)/, "\\1")
|
||||
if dst_md != sample_md
|
||||
print "Latex result didn't match !!\n"
|
||||
end
|
||||
else
|
||||
print "Unexpected error.\n"
|
||||
end
|
||||
end
|
||||
|
||||
# --- clean the temorary files
|
||||
dst_dirs.each do |d|
|
||||
if Dir.exist? d
|
||||
pathname = "#{d}/sample.md"
|
||||
File.delete pathname if File.exist? pathname
|
||||
Dir.rmdir d if Dir.empty? d
|
||||
end
|
||||
end
|
||||
system "rm", "-rf", "temp"
|
Loading…
Add table
Reference in a new issue