├── .gitignore
├── LICENSE
├── README.md
├── dub.json
├── linux.mak
├── makefile
├── me.html
├── src
└── med
│ ├── ansicolors.d
│ ├── basic.d
│ ├── buffer.d
│ ├── console.d
│ ├── disp.d
│ ├── display.d
│ ├── disprev.d
│ ├── ed.d
│ ├── file.d
│ ├── fileio.d
│ ├── line.d
│ ├── main.d
│ ├── more.d
│ ├── mouse.d
│ ├── random.d
│ ├── regexp.d
│ ├── region.d
│ ├── search.d
│ ├── spawn.d
│ ├── syntaxc.d
│ ├── syntaxcpp.d
│ ├── syntaxd.d
│ ├── tcap.d
│ ├── terminal.d
│ ├── termio.d
│ ├── testkbd.d
│ ├── url.d
│ ├── utf.d
│ ├── window.d
│ ├── word.d
│ └── xterm.d
└── win32.mak
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.obj
3 | .B*
4 | *~
5 | bin
6 | obj
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This version of microEmacs is based on the public domain C
2 | version written by Dave G. Conroy.
3 | The D programming language version is written by Walter Bright.
4 | This program is in the public domain.
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## med, Micro Emacs in D
3 |
4 | This is my version of MicroEmacs, based on the public
5 | domain version by Dave Conroy. I like it because it is
6 | small, fast, easilly customizable, and it ports readilly
7 | to whatever machine I need to use it on. It's written
8 | in the [D programming language](https://dlang.org).
9 |
10 | It currently works on Windows and Linux.
11 |
12 | To edit myfile.d:
13 | ```
14 | med myfile.d
15 | ```
16 |
17 | Cheat Sheet
18 | ```
19 | Command Name Description Keybinding
20 |
21 | Movement
22 |
23 | basic_nextline Move to next line F5
24 | gotobol Move to start of line ^A
25 | forwchar Move forward by characters ^F, rightarrow
26 | gotoeol Move to end of line ^E
27 | backchar Move backward by characters ^B, leftarrow
28 | forwline Move forward by lines ^N, downarrow
29 | backline Move backward by lines ^P, uparrow
30 | forwpage Move forward by pages ^V, PgDn
31 | backpage Move backward by pages Esc B, PgUp
32 | gotobob Move to start of buffer Esc <, ^Home
33 | gotoeob Move to end of buffer Esc >, ^End
34 | gotoline Move to line number ^X L
35 | word_back Backup by words Esc B, ^leftarrow
36 | word_forw Advance by words Esc F, ^rightarrow
37 |
38 | Windows
39 |
40 | window_next Move to the next window ^X N, F6
41 | window_prev Move to the previous window ^X P
42 | window_only Make current window only one ^X 1
43 | window_split Split current window ^X 2
44 | window_mvdn Move window down Esc N, End
45 | window_mvup Move window up Esc P, Home
46 | window_enlarge Enlarge display window ^X Z
47 | window_shrink Shrink window Esc Z
48 | window_reposition Reposition window ^X T
49 | window_refresh Refresh the screen ^L
50 | delwind Delete a window ^X D
51 |
52 | Deleting
53 |
54 | random_deblank Delete blank lines ^X O
55 | random_forwdel Forward delete ^D, Del
56 | random_backdel Backward delete ^H, 0x7F
57 | random_undelchar Undelete a character AltF Del
58 | Ddelline Delete a line ^J
59 | Dundelline Undelete a line Esc J, AltF F2
60 | Ddelword Delete a word
61 | Ddelbword Delete a word (backwards)
62 | Dundelword Undelete a word AltF ^rightarrow, AltF ^leftarrow
63 | delfword Delete forward word Esc D
64 | delbword Delete backward word Esc H
65 |
66 | Cutting/Pasting
67 |
68 | random_kill Kill forward ^K
69 | random_yank Paste from kill buffer ^Y, ^X K, F10
70 | region_kill Cut region to kill buffer Esc 9, F9
71 | region_copy Copy region to kill buffer Esc 8, F8
72 | basic_setmark Set mark F7, Esc .
73 | removemark Remove mark ^X .
74 | swapmark Swap dot and mark Esc X
75 | word_select Select word Esc W
76 |
77 | Files
78 |
79 | filenext Edit next file AltF N
80 | fileread Get a file, read only AltF R
81 | filevisit Get a file, read write AltF V
82 | filewrite Write a file AltF W
83 | fileunmodify Turn off buffer changed bits AltF U
84 | filesave Save current file AltF S
85 | filename Adjust file name AltF F
86 | filemodify Write modified files AltF M
87 | Dinsertfile Insert a file at dot AltF I
88 |
89 | Exit
90 |
91 | ctrlg Abort out of things ^@, ^G
92 | quit Quit ^C, AltF Q
93 | quickexit low keystroke style exit
94 | normexit Write modified files and exit AltF X, AltX
95 |
96 | Macros
97 |
98 | ctlxlp Begin macro ^X (
99 | ctlxrp End macro ^X )
100 | macrotoggle Start/End macro F12
101 | ctlxe Execute macro ^X E, F11
102 |
103 | Search
104 |
105 | forwsearch Search forward ^S
106 | Search forward regexp ^S^T
107 | Search forward word ^S^W
108 | backsearch Search backwards ^R
109 | replacestring Search and replace Esc R
110 | queryreplacestring Query search and replace Esc Q
111 | Dsearch Search F4, AltF F4
112 | Dsearchagain Search for the same string F2
113 |
114 | D, C and C++
115 |
116 | search_paren Toggle over parentheses ^W, F3
117 | random_indent Insert CR-LF, then indent
118 | random_incindent increase indentation level ^X ], AltF10
119 | random_decindent decrease indentation level ^X [, AltF9
120 | random_opttab optimize tabbing in line Esc I
121 | Dcppcomment convert /* */ to // ^X /
122 |
123 | Configuration
124 |
125 | display_norm_fg AltF2
126 | display_norm_bg AltF1
127 | display_mode_fg AltF4
128 | display_mode_bg AltF3
129 | display_mark_fg AltF5
130 | display_mark_bg AltF6
131 | display_eol_bg AltF7
132 | main_saveconfig Save configuration AltC
133 |
134 | Process
135 |
136 | spawncli Run CLI in a subjob ^Z
137 | spawn Run a command in a subjob ^X !
138 | spawn_filter Filter buffer through program ^X #
139 | spawn_pipe Run program and gather output ^X @, AltZ
140 | Dpause Pause the program (UNIX only)
141 |
142 | Buffers
143 |
144 | listbuffers Display list of buffers AltF B
145 | usebuffer Switch a window to a buffer ^X B
146 | buffer_next Switch to next buffer ^X W, AltB
147 | killbuffer Make a buffer go away
148 |
149 | Other
150 |
151 | random_setfillcol Set fill column ^X F
152 | word_wrap_line Word wrap line ^X A
153 | random_showcpos Show the cursor position ^X =
154 | random_twiddle Twiddle characters ^T
155 | random_tab Insert tab ^I, Tab
156 | random_hardtab Set hardware tabs AltF T
157 | random_newline Insert CR-LF ^M
158 | random_openline Open up a blank line ^O, AltF Ins
159 | random_quote Insert literal ^Q, ^X Q
160 | region_togglemode Toggle column region mode Esc T
161 | toggleinsert Toggle insert/overwrite mode Ins
162 | line_overwrite Write char in overwrite mode
163 | getcol Get current column
164 | misc_upper Upper case word/region Esc U
165 | misc_lower Lower case word/region Esc L
166 | capword Initial capitalize word Esc C
167 | win32toggle43 Toggle hires mode AltE
168 | ibmpctoggle43 Toggle hires mode AltE
169 | Dignore do nothing
170 | Dadvance Set into advance mode Esc downarrow
171 | Dbackup Set into backup mode Esc uparrow
172 | Dinsertdate File and date stamp AltF D
173 | scrollUnicode Scroll through Unicode variations ^X U
174 | ```
175 |
176 | ### Glossary
177 |
178 | * *dot* current cursor position
179 | * *mark* start of a region
180 | * *minibuffer* text entry box used for entering file names
181 | and search strings
182 | * *region* text between "dot" and "mark"
183 | * [Regular Expressions](https://www.digitalmars.com/ctg/regular.html)
184 |
185 |
186 | ### Notes
187 |
188 | * ^[ also works as Esc.
189 | * Names without a keybinding can't be accessed, but they can
190 | be called if the keybindings in main.c are updated.
191 | * Prefixing a command with ^U enables a count to be entered,
192 | which executes the command count times.
193 | * Pressing ^X, AltF, or Esc and then pausing will bring up
194 | a menu.
195 | * The right mouse button will bring up a menu.
196 | * The left mouse button can be used for setting the dot,
197 | marking regions, and adjusting window sizes.
198 | * The minibuffer has a small history buffer, accessible with
199 | the uparrow key.
200 | * On Win32, by clicking on the title bar, then select [Edit],
201 | you can access the Windows clipboard. This is very handy
202 | for cutting/pasting text from another window or the web browser.
203 |
204 | ### Bugs
205 |
206 | * Some of the keybindings make no sense.
207 | * The Alt function key sequences don't work on Win32.
208 | * The control numeric pad sequences don't work on Linux.
209 | * The colors can't be modified on any but the DOS version.
210 | * The process functionality is flaky.
211 | * For some reason, the mouse in the Win32 version doesn't
212 | work on Win2000, but does on WinNT.
213 |
--------------------------------------------------------------------------------
/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "med",
3 | "description": "MicroEmacs written in D",
4 | "authors": ["Dave G. Conroy", "Walter Bright"],
5 | "homepage": "https://github.com/DigitalMars/med",
6 | "license": "public domain",
7 | "targetType": "executable",
8 | "targetName": "med",
9 | "targetPath": "bin",
10 | "sourcePaths": ["src/med"],
11 | "importPaths": ["src/med"],
12 | }
13 |
--------------------------------------------------------------------------------
/linux.mak:
--------------------------------------------------------------------------------
1 | #_ linux.mak
2 |
3 | DMD=dmd
4 | MODEL=32
5 | S=src/med
6 | O=obj
7 | B=bin
8 |
9 | DFLAGS=-g -od$O -I$S -m$(MODEL)
10 | LDFLG=-g \
11 | -L~/cbx/mars/phobos/generated/linux/release/32 \
12 | -L~/cbx/mars/phobos/generated/linux/release/64 \
13 |
14 |
15 | .d.o:
16 | $(DMD) -c $(DFLAGS) $*
17 |
18 | all: $B/med
19 |
20 | SRC= $S/ed.d $S/basic.d $S/buffer.d $S/display.d $S/file.d $S/fileio.d $S/line.d \
21 | $S/random.d $S/region.d $S/search.d $S/spawn.d $S/terminal.d \
22 | $S/window.d $S/word.d $S/main.d $S/more.d $S/disprev.d \
23 | $S/syntaxd.d $S/syntaxc.d $S/syntaxcpp.d $S/termio.d $S/xterm.d \
24 | $S/tcap.d $S/console.d $S/mouse.d $S/disp.d $S/url.d $S/utf.d $S/regexp.d
25 |
26 |
27 | OBJ= $O/ed.o $O/basic.o $O/buffer.o $O/display.o $O/file.o $O/fileio.o $O/line.o \
28 | $O/random.o $O/region.o $O/search.o $O/spawn.o $O/terminal.o \
29 | $O/window.o $O/word.o $O/main.o $O/more.o $O/disprev.o \
30 | $O/syntaxd.o $O/syntaxc.o $O/syntaxcpp.o $O/termio.o $O/xterm.o \
31 | $O/tcap.o $O/console.o $O/mouse.o $O/disp.o $O/url.o $O/utf.o $O/regexp.o
32 |
33 | SOURCE= $(SRC) win32.mak linux.mak me.html
34 |
35 | $B/med : $(OBJ) linux.mak
36 | $(DMD) $(DFLAGS) -of$B/med $(OBJ)
37 |
38 | ansicolors : $S/ansicolors.d
39 | $(DMD) $(DFLAGS) -of$B/ansicolors $S/ansicolors.d
40 |
41 | $O/ed.o: $S/ed.d
42 | $(DMD) -c $(DFLAGS) $S/ed.d
43 |
44 | $O/basic.o: $S/basic.d
45 | $(DMD) -c $(DFLAGS) $S/basic.d
46 |
47 | $O/buffer.o: $S/buffer.d
48 | $(DMD) -c $(DFLAGS) $S/buffer.d
49 |
50 | $O/console.o: $S/console.d
51 | $(DMD) -c $(DFLAGS) $S/console.d
52 |
53 | $O/disp.o: $S/disp.d
54 | $(DMD) -c $(DFLAGS) $S/disp.d
55 |
56 | $O/display.o: $S/display.d
57 | $(DMD) -c $(DFLAGS) $S/display.d
58 |
59 | $O/file.o: $S/file.d
60 | $(DMD) -c $(DFLAGS) $S/file.d
61 |
62 | $O/fileio.o: $S/fileio.d
63 | $(DMD) -c $(DFLAGS) $S/fileio.d
64 |
65 | $O/line.o: $S/line.d
66 | $(DMD) -c $(DFLAGS) $S/line.d
67 |
68 | $O/mouse.o: $S/mouse.d
69 | $(DMD) -c $(DFLAGS) $S/mouse.d
70 |
71 | $O/random.o: $S/random.d
72 | $(DMD) -c $(DFLAGS) $S/random.d
73 |
74 | $O/regexp.o: $S/regexp.d
75 | $(DMD) -c $(DFLAGS) $S/regexp.d
76 |
77 | $O/region.o: $S/region.d
78 | $(DMD) -c $(DFLAGS) $S/region.d
79 |
80 | $O/search.o: $S/search.d
81 | $(DMD) -c $(DFLAGS) $S/search.d
82 |
83 | $O/spawn.o: $S/spawn.d
84 | $(DMD) -c $(DFLAGS) $S/spawn.d
85 |
86 | $O/terminal.o: $S/terminal.d
87 | $(DMD) -c $(DFLAGS) $S/terminal.d
88 |
89 | $O/termio.o: $S/termio.d
90 | $(DMD) -c $(DFLAGS) $S/termio.d
91 |
92 | $O/url.o: $S/url.d
93 | $(DMD) -c $(DFLAGS) $S/url.d
94 |
95 | $O/window.o: $S/window.d
96 | $(DMD) -c $(DFLAGS) $S/window.d
97 |
98 | $O/word.o: $S/word.d
99 | $(DMD) -c $(DFLAGS) $S/word.d
100 |
101 | $O/main.o: $S/main.d
102 | $(DMD) -c $(DFLAGS) $S/main.d
103 |
104 | $O/more.o: $S/more.d
105 | $(DMD) -c $(DFLAGS) $S/more.d
106 |
107 | $O/disprev.o: $S/disprev.d
108 | $(DMD) -c $(DFLAGS) $S/disprev.d
109 |
110 | $O/syntaxd.o: $S/syntaxd.d
111 | $(DMD) -c $(DFLAGS) $S/syntaxd.d
112 |
113 | $O/syntaxc.o: $S/syntaxc.d
114 | $(DMD) -c $(DFLAGS) $S/syntaxc.d
115 |
116 | $O/syntaxcpp.o: $S/syntaxcpp.d
117 | $(DMD) -c $(DFLAGS) $S/syntaxcpp.d
118 |
119 | $O/tcap.o: $S/tcap.d
120 | $(DMD) -c $(DFLAGS) $S/tcap.d
121 |
122 | $O/utf.o: $S/utf.d
123 | $(DMD) -c $(DFLAGS) $S/utf.d
124 |
125 | $O/xterm.o: $S/xterm.d
126 | $(DMD) -c $(DFLAGS) $S/xterm.d
127 |
128 | clean:
129 | rm $O/*.o
130 |
131 | detab : $(SRC)
132 | detab $(SRC)
133 |
134 | zip : $(SOURCE)
135 | rm -f me.zip
136 | zip me $(SOURCE)
137 |
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | MODEL=32
2 |
3 | #HOST_DMD=/usr/bin/dmd
4 | #HOST_DMD=/home/walter/dmd2.067/linux/bin64/dmd
5 | #HOST_DMD=/home/walter/dmd2.074.1/linux/bin64/dmd
6 | #HOST_DMD=/home/walter/dmd2.079.1/linux/bin64/dmd
7 | HOST_DMD=/home/walter/dmd2.089.1/linux/bin64/dmd
8 | #HOST_DMD=/home/walter/cbx/mars/dmd2
9 | #HOST_DMD=/home/walter/forks/dmd/generated/linux/release/64/dmd
10 |
11 | MAKE=make DMD=$(HOST_DMD) MODEL=$(MODEL) -f linux.mak
12 |
13 | targets:
14 | $(MAKE)
15 |
16 | ansicolors:
17 | $(MAKE) ansicolors
18 |
19 | detab:
20 | $(MAKE) detab
21 |
22 | clean:
23 | $(MAKE) clean
24 |
25 | zip:
26 | $(MAKE) zip
27 |
--------------------------------------------------------------------------------
/me.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Digital Mars - MicroEmacs (Text Editor)
5 |
6 |
7 |
8 |
9 | [Home]
10 | [Search]
11 | [CTG]
12 | [RTL]
13 | [IDDE]
14 | [STL]
15 | [Shop]
16 |
17 |
18 | MicroEmacs
19 |
20 | This is my version of MicroEmacs, based on the public
21 | domain version by Dave Conroy. I like it because it is
22 | small, fast, easilly customizable, and it ports readilly
23 | to whatever machine I need to use it on.
24 |
25 |
26 | This version is also in the public domain.
27 |
28 |
29 | -Walter Bright
30 | www.digitalmars.com
31 |
32 |
33 | men.exe Win32 executable
34 | mex.exe DOS32 executable
35 | medos.exe DOS executable
36 | melinux Linux executable
37 |
38 | Command Name Description Keybinding
39 |
40 | Movement
41 |
42 | basic_nextline Move to next line F5
43 | gotobol Move to start of line ^A
44 | forwchar Move forward by characters ^F, rightarrow
45 | gotoeol Move to end of line ^E
46 | backchar Move backward by characters ^B, leftarrow
47 | forwline Move forward by lines ^N, downarrow
48 | backline Move backward by lines ^P, uparrow
49 | forwpage Move forward by pages ^V, PgDn
50 | backpage Move backward by pages Esc B, PgUp
51 | gotobob Move to start of buffer Esc <, ^Home
52 | gotoeob Move to end of buffer Esc >, ^End
53 | gotoline Move to line number ^X L
54 | word_back Backup by words Esc B, ^leftarrow
55 | word_forw Advance by words Esc F, ^rightarrow
56 |
57 | Windows
58 |
59 | window_next Move to the next window ^X N, F6
60 | window_prev Move to the previous window ^X P
61 | window_only Make current window only one ^X 1
62 | window_split Split current window ^X 2
63 | window_mvdn Move window down Esc N, End
64 | window_mvup Move window up Esc P, Home
65 | window_enlarge Enlarge display window ^X Z
66 | window_shrink Shrink window Esc Z
67 | window_reposition Reposition window ^X T
68 | window_refresh Refresh the screen ^L
69 | delwind Delete a window ^X D
70 |
71 | Deleting
72 |
73 | random_deblank Delete blank lines ^X O
74 | random_forwdel Forward delete ^D, Del
75 | random_backdel Backward delete ^H, 0x7F
76 | random_undelchar Undelete a character AltF Del
77 | Ddelline Delete a line ^J
78 | Dundelline Undelete a line Esc J, AltF F2
79 | Ddelword Delete a word
80 | Ddelbword Delete a word (backwards)
81 | Dundelword Undelete a word AltF ^rightarrow, AltF ^leftarrow
82 | delfword Delete forward word Esc D
83 | delbword Delete backward word Esc H
84 |
85 | Cutting/Pasting
86 |
87 | random_kill Kill forward ^K
88 | random_yank Paste from kill buffer ^Y, ^X K, F10
89 | region_kill Cut region to kill buffer Esc 9, F9
90 | region_copy Copy region to kill buffer Esc 8, F8
91 | basic_setmark Set mark F7, Esc .
92 | removemark Remove mark ^X .
93 | swapmark Swap dot and mark Esc X
94 | word_select Select word Esc W
95 |
96 | Files
97 |
98 | filenext Edit next file AltF N
99 | fileread Get a file, read only AltF R
100 | filevisit Get a file, read write AltF V
101 | filewrite Write a file AltF W
102 | fileunmodify Turn off buffer changed bits AltF U
103 | filesave Save current file AltF S
104 | filename Adjust file name AltF F
105 | filemodify Write modified files AltF M
106 | Dinsertfile Insert a file at dot AltF I
107 |
108 | Exit
109 |
110 | ctrlg Abort out of things ^@, ^G
111 | quit Quit ^C, AltF Q
112 | quickexit low keystroke style exit
113 | normexit Write modified files and exit AltF X, AltX
114 |
115 | Macros
116 |
117 | ctlxlp Begin macro ^X (
118 | ctlxrp End macro ^X )
119 | macrotoggle Start/End macro F12
120 | ctlxe Execute macro ^X E, F11
121 |
122 | Search
123 |
124 | forwsearch Search forward ^S
125 | Search forward regexp ^S^T
126 | Search forward word ^S^W
127 | backsearch Search backwards ^R
128 | replacestring Search and replace Esc R
129 | queryreplacestring Query search and replace Esc Q
130 | Dsearch Search F4, AltF F4
131 | Dsearchagain Search for the same string F2
132 |
133 | C and C++
134 |
135 | search_paren Toggle over parentheses ^W, F3
136 | random_indent Insert CR-LF, then indent
137 | random_incindent increase indentation level ^X ], AltF10
138 | random_decindent decrease indentation level ^X [, AltF9
139 | random_opttab optimize tabbing in line Esc I
140 | Dcppcomment convert /* */ to // ^X /
141 |
142 | Configuration
143 |
144 | display_norm_fg AltF2
145 | display_norm_bg AltF1
146 | display_mode_fg AltF4
147 | display_mode_bg AltF3
148 | display_mark_fg AltF5
149 | display_mark_bg AltF6
150 | display_eol_bg AltF7
151 | main_saveconfig Save configuration AltC
152 |
153 | Process
154 |
155 | spawncli Run CLI in a subjob ^Z
156 | spawn Run a command in a subjob ^X !
157 | spawn_filter Filter buffer through program ^X #
158 | spawn_pipe Run program and gather output ^X @, AltZ
159 | Dpause Pause the program (UNIX only)
160 |
161 | Buffers
162 |
163 | listbuffers Display list of buffers AltF B
164 | usebuffer Switch a window to a buffer ^X B
165 | buffer_next Switch to next buffer ^X W, AltB
166 | killbuffer Make a buffer go away
167 |
168 | Other
169 |
170 | random_setfillcol Set fill column ^X F
171 | word_wrap_line Word wrap line ^X A
172 | random_showcpos Show the cursor position ^X =
173 | random_twiddle Twiddle characters ^T
174 | random_tab Insert tab ^I, Tab
175 | random_hardtab Set hardware tabs AltF T
176 | random_newline Insert CR-LF ^M
177 | random_openline Open up a blank line ^O, AltF Ins
178 | random_quote Insert literal ^Q, ^X Q
179 | region_togglemode Toggle column region mode Esc T
180 | toggleinsert Toggle insert/overwrite mode Ins
181 | line_overwrite Write char in overwrite mode
182 | getcol Get current column
183 | misc_upper Upper case word/region Esc U
184 | misc_lower Lower case word/region Esc L
185 | capword Initial capitalize word Esc C
186 | win32toggle43 Toggle hires mode AltE
187 | ibmpctoggle43 Toggle hires mode AltE
188 | Dignore do nothing
189 | Dadvance Set into advance mode Esc downarrow
190 | Dbackup Set into backup mode Esc uparrow
191 | Dinsertdate File and date stamp AltF D
192 | scrollUnicode Scroll through Unicode variations ^X U
193 |
194 |
195 | Glossary
196 |
197 |
198 | - dot
- current cursor position
199 |
- mark
- start of a region
200 |
- minibuffer
- text entry box used for entering file names
201 | and search strings
202 |
- region
- text between "dot" and "mark"
203 |
- Regular Expressions
204 |
205 |
206 | Notes
207 |
208 |
209 | - ^[ also works as Esc.
210 |
- Names without a keybinding can't be accessed, but they can
211 | be called if the keybindings in main.c are updated.
212 |
- Prefixing a command with ^U enables a count to be entered,
213 | which executes the command count times.
214 |
- Pressing ^X, AltF, or Esc and then pausing will bring up
215 | a menu.
216 |
- The right mouse button will bring up a menu.
217 |
- The left mouse button can be used for setting the dot,
218 | marking regions, and adjusting window sizes.
219 |
- The minibuffer has a small history buffer, accessible with
220 | the uparrow key.
221 |
- On Win32, by clicking on the title bar, then select [Edit],
222 | you can access the Windows clipboard. This is very handy
223 | for cutting/pasting text from another window or the web browser.
224 |
225 |
226 | Bugs
227 |
228 |
229 | - Some of the keybindings make no sense.
230 |
- The Alt function key sequences don't work on Win32.
231 |
- The control numeric pad sequences don't work on Linux.
232 |
- The colors can't be modified on any but the DOS version.
233 |
- The process functionality is flaky.
234 |
- For some reason, the mouse in the Win32 version doesn't
235 | work on Win2000, but does on WinNT.
236 |
237 |
238 |
239 |
240 |
--------------------------------------------------------------------------------
/src/med/ansicolors.d:
--------------------------------------------------------------------------------
1 | /*******************************************
2 | * Print various ANSI escape sequences to the screen.
3 | */
4 |
5 | module ansicolors;
6 |
7 | import core.stdc.stdio;
8 |
9 | void main()
10 | {
11 | // Escape sequences:
12 | // https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences
13 | // https://opensource.com/article/19/9/linux-terminal-colors
14 |
15 | string s = "text sequence";
16 | foreach (i; 30 .. 37+1)
17 | {
18 | printf("\\033[%dm \033[%dm %s\n", i, i, s.ptr);
19 | resetColor();
20 | }
21 | foreach (i; 30 .. 37+1)
22 | {
23 | printf("\\033[1;%dm \033[1;%dm %s\n", i, i, s.ptr);
24 | resetColor();
25 | }
26 | foreach (i; 40 .. 47+1)
27 | {
28 | printf("\\033[%dm \033[%dm %s", i, i, s.ptr);
29 | resetColor();
30 | printf("\n");
31 | }
32 | foreach (i; 0 .. 10+1)
33 | {
34 | printf("\\033[%d;30m \033[%d;30m %s\n", i, i, s.ptr);
35 | resetColor();
36 | }
37 | foreach (i; 51 .. 53+1)
38 | {
39 | printf("\\033[%d;30m \033[%d;30m %s\n", i, i, s.ptr);
40 | resetColor();
41 | }
42 | }
43 |
44 | void resetColor()
45 | {
46 | fputs("\033[m", stdout);
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/src/med/basic.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 | /*
11 | * The routines in this file move the cursor around on the screen. They
12 | * compute a new value for the cursor, then adjust ".". The display code
13 | * always updates the cursor location, so only moves between lines, or
14 | * functions that adjust the top line in the window and invalidate the
15 | * framing, are hard.
16 | */
17 |
18 | module basic;
19 |
20 | import std.conv;
21 |
22 | import ed;
23 | import line;
24 | import main;
25 | import window;
26 | import display;
27 | import console;
28 |
29 | /*********************************
30 | * Move the cursor to the
31 | * beginning of the current line.
32 | * Trivial.
33 | */
34 |
35 | int gotobol(bool f, int n)
36 | { int s;
37 |
38 | if (curwp.w_doto == 0)
39 | s = backline(f, n);
40 | else
41 | {
42 | if (curwp.w_markp)
43 | curwp.w_flag |= WFMOVE;
44 | s = TRUE;
45 | curwp.w_doto = 0;
46 | if( n > 1 )
47 | s = backline(f, n-1);
48 | }
49 | curgoal = 0;
50 | return s;
51 | }
52 |
53 | /*
54 | * Move the cursor backwards by "n" characters. If "n" is less than zero call
55 | * "forwchar" to actually do the move. Otherwise compute the new cursor
56 | * location. Error if you try and move out of the buffer. Set the flag if the
57 | * line pointer for dot changes.
58 | */
59 | int backchar(bool f, int n)
60 | {
61 | if (n < 0)
62 | return (forwchar(f, -n));
63 | if (curwp.w_markp && n)
64 | curwp.w_flag |= WFMOVE;
65 | while (n--) {
66 | if (curwp.w_doto == 0) {
67 | LINE *lp;
68 | if ((lp=lback(curwp.w_dotp)) == curbp.b_linep)
69 | return (FALSE);
70 | curwp.w_dotp = lp;
71 | curwp.w_doto = llength(lp);
72 | curwp.w_flag |= WFMOVE;
73 | } else
74 | curwp.w_doto--;
75 | }
76 | return (TRUE);
77 | }
78 |
79 | /**************************************
80 | * Move the cursor to the end of the current line.
81 | * If already at the end, advance to next line.
82 | */
83 |
84 | int gotoeol(bool f, int n)
85 | {
86 | int s;
87 |
88 | s = TRUE;
89 | if( curwp.w_doto != llength(curwp.w_dotp) )
90 | {
91 | if (curwp.w_markp)
92 | curwp.w_flag |= WFMOVE;
93 | n--;
94 | }
95 | if( n > 0 )
96 | s = forwline(f,n);
97 | curwp.w_doto = llength(curwp.w_dotp);
98 | return( s );
99 | }
100 |
101 | /*
102 | * Move the cursor forwards by "n" characters. If "n" is less than zero call
103 | * "backchar" to actually do the move. Otherwise compute the new cursor
104 | * location, and move ".". Error if you try and move off the end of the
105 | * buffer. Set the flag if the line pointer for dot changes.
106 | */
107 | int forwchar(bool f, int n)
108 | {
109 | if (n < 0)
110 | return (backchar(f, -n));
111 | if (curwp.w_markp && n)
112 | curwp.w_flag |= WFMOVE;
113 | while (n--) {
114 | if (curwp.w_doto == llength(curwp.w_dotp)) {
115 | if (curwp.w_dotp == curbp.b_linep)
116 | return (FALSE);
117 | curwp.w_dotp = lforw(curwp.w_dotp);
118 | curwp.w_doto = 0;
119 | curwp.w_flag |= WFMOVE;
120 | } else
121 | curwp.w_doto++;
122 | }
123 | return (TRUE);
124 | }
125 |
126 | /*
127 | * Goto the beginning of the buffer. Massive adjustment of dot. This is
128 | * considered to be hard motion; it really isn't if the original value of dot
129 | * is the same as the new value of dot. Normally bound to "M-<".
130 | */
131 | int gotobob(bool f, int n)
132 | {
133 | curwp.w_dotp = lforw(curbp.b_linep);
134 | curwp.w_doto = 0;
135 | curwp.w_flag |= WFHARD;
136 | return (TRUE);
137 | }
138 |
139 | /*
140 | * Move to the end of the buffer. Dot is always put at the end of the file
141 | * (ZJ). The standard screen code does most of the hard parts of update.
142 | * Bound to "M.".
143 | */
144 | int gotoeob(bool f, int n)
145 | {
146 | curwp.w_dotp = curbp.b_linep;
147 | curwp.w_doto = 0;
148 | curwp.w_flag |= WFHARD;
149 | return (TRUE);
150 | }
151 |
152 | /*
153 | * Move forward by full lines. If the number of lines to move is less than
154 | * zero, call the backward line function to actually do it. The last command
155 | * controls how the goal column is set. Bound to "C-N". No errors are
156 | * possible.
157 | */
158 | int forwline(bool f, int n)
159 | {
160 | if (n < 0)
161 | return (backline(f, -n));
162 | auto dlp = curwp.w_dotp;
163 |
164 | /* Reset goal if last command not backline() or forwline() */
165 | if ((lastflag&CFCPCN) == 0)
166 | curgoal = getcol(dlp,curwp.w_doto);
167 | thisflag |= CFCPCN; /* this command was a */
168 | /* forwline or backline */
169 | while (n-- && dlp!=curbp.b_linep)
170 | dlp = lforw(dlp);
171 | curwp.w_dotp = dlp;
172 | curwp.w_doto = getgoal(dlp);
173 | curwp.w_flag |= WFMOVE;
174 | return (TRUE);
175 | }
176 |
177 | /*******************************
178 | * Proceed to beginning of next line.
179 | */
180 |
181 | int basic_nextline(bool f, int n)
182 | {
183 | if (curwp.w_doto == 0 || gotobol(FALSE,1))
184 | {
185 | lastflag &= ~CFCPCN;
186 | return forwline(f,n);
187 | }
188 | return FALSE;
189 | }
190 |
191 | /*
192 | * This function is like "forwline", but goes backwards. The scheme is exactly
193 | * the same. Check for arguments that are less than zero and call your
194 | * alternate. Figure out the new line and call "movedot" to perform the
195 | * motion. No errors are possible. Bound to "C-P".
196 | */
197 | int backline(bool f, int n)
198 | {
199 | if (n < 0)
200 | return (forwline(f, -n));
201 | auto dlp = curwp.w_dotp;
202 |
203 | /* Reset goal if last command not backline() or forwline() */
204 | if ((lastflag&CFCPCN) == 0)
205 | curgoal = getcol(dlp,curwp.w_doto);
206 | thisflag |= CFCPCN;
207 |
208 | while (n-- && lback(dlp)!=curbp.b_linep)
209 | dlp = lback(dlp);
210 | curwp.w_dotp = dlp;
211 | curwp.w_doto = getgoal(dlp);
212 | curwp.w_flag |= WFMOVE;
213 | return (TRUE);
214 | }
215 |
216 | /**********************************
217 | * Goto line number.
218 | */
219 |
220 | int gotoline(bool f, int n)
221 | { string number;
222 |
223 | if (mlreply("Goto line: ", null, number) == FALSE)
224 | return FALSE;
225 | try
226 | {
227 | const num = to!(int)(number);
228 | gotobob(f, n); /* move to beginning of buffer */
229 | return forwline(f, num - 1);
230 | }
231 | catch (Throwable o)
232 | {
233 | }
234 | return FALSE;
235 | }
236 |
237 | /*
238 | * This routine, given a pointer to a LINE, and the current cursor goal
239 | * column, return the best choice for the offset. The offset is returned.
240 | * Used by forwline() and backline().
241 | */
242 | int getgoal(LINE* dlp)
243 | {
244 | int c;
245 | int col;
246 | int newcol;
247 | int dbo;
248 |
249 | col = 0;
250 | dbo = 0;
251 | while (dbo != llength(dlp)) {
252 | c = lgetc(dlp, dbo);
253 | newcol = col;
254 | if (c == '\t')
255 | newcol |= 0x07;
256 | else if (c<0x20 || c==0x7F)
257 | ++newcol;
258 | ++newcol;
259 | if (newcol > curgoal)
260 | break;
261 | col = newcol;
262 | ++dbo;
263 | }
264 | return (dbo);
265 | }
266 |
267 | /*
268 | * Scroll forward by a specified number of lines, or by a full page if no
269 | * argument. Bound to "C-V". The "2" in the arithmetic on the window size is
270 | * the overlap; this value is the default overlap value in ITS EMACS. Because
271 | * this zaps the top line in the display window, we have to do a hard update.
272 | */
273 | int forwpage(bool f, int n)
274 | {
275 | if (f == FALSE) {
276 | n = curwp.w_ntrows - 2; /* Default scroll. */
277 | if (n <= 0) /* Forget the overlap */
278 | n = 1; /* if tiny window. */
279 | } else if (n < 0)
280 | return (backpage(f, -n));
281 | else if (CVMVAS) /* Convert from pages */
282 | n *= curwp.w_ntrows; /* to lines. */
283 | auto lp = curwp.w_linep;
284 | while (n-- && lp!=curbp.b_linep)
285 | lp = lforw(lp);
286 | curwp.w_linep = lp;
287 | curwp.w_dotp = lp;
288 | curwp.w_doto = 0;
289 | curwp.w_flag |= WFHARD;
290 | return (TRUE);
291 | }
292 |
293 | /*
294 | * This command is like "forwpage", but it goes backwards. The "2", like
295 | * above, is the overlap between the two windows. The value is from the ITS
296 | * EMACS manual. Bound to "M-V". We do a hard update for exactly the same
297 | * reason.
298 | */
299 | int backpage(bool f, int n)
300 | {
301 | if (f == FALSE) {
302 | n = curwp.w_ntrows - 2; /* Default scroll. */
303 | if (n <= 0) /* Don't blow up if the */
304 | n = 1; /* window is tiny. */
305 | } else if (n < 0)
306 | return (forwpage(f, -n));
307 | else if (CVMVAS) /* Convert from pages */
308 | n *= curwp.w_ntrows; /* to lines. */
309 | auto lp = curwp.w_linep;
310 | while (n-- && lback(lp)!=curbp.b_linep)
311 | lp = lback(lp);
312 | curwp.w_linep = lp;
313 | curwp.w_dotp = lp;
314 | curwp.w_doto = 0;
315 | curwp.w_flag |= WFHARD;
316 | return (TRUE);
317 | }
318 |
319 | /*
320 | * Set the mark in the current window to the value of "." in the window. No
321 | * errors are possible. Bound to "M-.".
322 | */
323 | int basic_setmark(bool f, int n)
324 | {
325 | removemark(f,n); /* delete old mark */
326 | curwp.w_markp = curwp.w_dotp;
327 | curwp.w_marko = curwp.w_doto;
328 | /* Get starting column for column regions */
329 | markcol = getcol(curwp.w_markp,curwp.w_doto);
330 | mlwrite("[Mark set]");
331 | return (TRUE);
332 | }
333 |
334 | /*************************
335 | * Remove mark from current window.
336 | */
337 |
338 | int removemark(bool f, int n)
339 | {
340 | if (curwp.w_markp)
341 | { curwp.w_flag |= WFHARD;
342 | curwp.w_markp = null;
343 | mlwrite("[Mark removed]");
344 | }
345 | else
346 | mlwrite("[No mark]");
347 | return (TRUE);
348 | }
349 |
350 | /*
351 | * Swap the values of "." and "mark" in the current window. This is pretty
352 | * easy, bacause all of the hard work gets done by the standard routine
353 | * that moves the mark about. The only possible error is "no mark". Bound to
354 | * "C-X C-X".
355 | */
356 | int swapmark(bool f, int n)
357 | {
358 | if (curwp.w_markp == null) {
359 | mlwrite("No mark in this window");
360 | return (FALSE);
361 | }
362 | auto odotp = curwp.w_dotp;
363 | auto odoto = curwp.w_doto;
364 | curwp.w_dotp = curwp.w_markp;
365 | curwp.w_doto = curwp.w_marko;
366 | curwp.w_markp = odotp;
367 | curwp.w_marko = odoto;
368 | curwp.w_flag |= WFMOVE;
369 | return (TRUE);
370 | }
371 |
--------------------------------------------------------------------------------
/src/med/buffer.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 | /*
11 | * Buffer management.
12 | * Some of the functions are internal,
13 | * and some are actually attached to user
14 | * keys. Like everyone else, they set hints
15 | * for the display system.
16 | */
17 |
18 | module buffer;
19 |
20 | import std.stdio;
21 | import std.path;
22 |
23 | import core.memory;
24 |
25 | import ed;
26 | import line;
27 | import display;
28 | import main;
29 | import window;
30 |
31 |
32 | /*
33 | * Text is kept in buffers. A buffer header, described below, exists for every
34 | * buffer in the system. The buffers are kept in a big list, so that commands
35 | * that search for a buffer by name can find the buffer header. There is a
36 | * safe store for the dot and mark in the header, but this is only valid if
37 | * the buffer is not being displayed (that is, if "b_nwnd" is 0). The text for
38 | * the buffer is kept in a circularly linked list of lines, with a pointer to
39 | * the header line in "b_linep".
40 | */
41 | struct BUFFER {
42 | LINE* b_dotp; // Link to "." LINE structure
43 | uint b_doto; // Offset of "." in above LINE
44 | LINE* b_markp; // The same as the above two,
45 | uint b_marko; // but for the "mark"
46 | LINE* b_linep; // Link to the header LINE
47 | uint b_nwnd; // Count of windows on buffer
48 | ubyte b_flag; // Flags
49 | string b_fname; // File name
50 | string b_bname; // Buffer name
51 | Language b_lang = Language.text; // for color syntax highlighting
52 |
53 | /**********************************
54 | * Set filename associated with buffer.
55 | * Determine the language based on the filename.
56 | */
57 | void setFilename(string fname)
58 | {
59 | if (filenameCmp(b_fname, fname))
60 | {
61 | const lang = filenameCmp(extension(fname), ".d") == 0 ? Language.D :
62 | filenameCmp(extension(fname), ".di") == 0 ? Language.D :
63 | filenameCmp(extension(fname), ".c") == 0 ? Language.C :
64 | filenameCmp(extension(fname), ".cpp") == 0 ? Language.CPP :
65 | filenameCmp(extension(fname), ".c++") == 0 ? Language.CPP :
66 | Language.text;
67 | if (b_lang != lang)
68 | {
69 | b_lang = lang;
70 | }
71 | }
72 | b_fname = fname;
73 | }
74 | }
75 |
76 | enum
77 | {
78 | BFTEMP = 0x01, // Internal temporary buffer
79 | BFCHG = 0x02, // Changed since last write
80 | BFRDONLY = 0x04, // Buffer is read only
81 | BFNOCR = 0x08, // last line in buffer has no
82 | // trailing CR
83 | }
84 |
85 | enum Language
86 | {
87 | text = 0, // plain text (must be 0)
88 | D, // D programming language
89 | C, // C programming language
90 | CPP, // C++ programming language
91 | }
92 |
93 | __gshared BUFFER*[] buffers;
94 |
95 | /*
96 | * Attach a buffer to a window. The
97 | * values of dot and mark come from the buffer
98 | * if the use count is 0. Otherwise, they come
99 | * from some other window.
100 | */
101 | int usebuffer(bool f, int n)
102 | {
103 | string bufn;
104 |
105 | auto s = mlreply("Use buffer: ", null, bufn);
106 | if (s != TRUE)
107 | return (s);
108 | auto bp = buffer_find(bufn, TRUE, 0);
109 | if (bp == null)
110 | return (FALSE);
111 | return buffer_switch(bp);
112 | }
113 |
114 | /*********************************
115 | * Make next buffer in list the current one.
116 | * Put it into the current window if it isn't displayed.
117 | */
118 |
119 | int buffer_next(bool f, int n)
120 | {
121 | foreach (i, bp; buffers)
122 | {
123 | if (bp == curbp)
124 | {
125 | i = i + 1;
126 | if (i == buffers.length)
127 | i = 0;
128 | return buffer_switch(buffers[i]);
129 | }
130 | }
131 | return FALSE;
132 | }
133 |
134 | /***************************
135 | * Switch to buffer bp.
136 | * Returns:
137 | * TRUE or FALSE
138 | */
139 |
140 | int buffer_switch(BUFFER* bp)
141 | {
142 | if (--curbp.b_nwnd == 0) { /* Last use. */
143 | curbp.b_dotp = curwp.w_dotp;
144 | curbp.b_doto = curwp.w_doto;
145 | curbp.b_markp = curwp.w_markp;
146 | curbp.b_marko = curwp.w_marko;
147 | }
148 | curbp = bp; /* Switch. */
149 | curwp.w_bufp = bp;
150 | curwp.w_linep = bp.b_linep; /* For macros, ignored. */
151 | curwp.w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */
152 | if (bp.b_nwnd++ == 0) { /* First use. */
153 | curwp.w_dotp = bp.b_dotp;
154 | curwp.w_doto = bp.b_doto;
155 | curwp.w_markp = bp.b_markp;
156 | curwp.w_marko = bp.b_marko;
157 | return (TRUE);
158 | }
159 | else
160 | {
161 | /* Look for the existing window onto buffer bp */
162 | foreach (wp; windows)
163 | {
164 | if (wp!=curwp && wp.w_bufp==bp)
165 | {
166 | curwp.w_dotp = wp.w_dotp;
167 | curwp.w_doto = wp.w_doto;
168 | curwp.w_markp = wp.w_markp;
169 | curwp.w_marko = wp.w_marko;
170 | break;
171 | }
172 | }
173 | }
174 | return TRUE;
175 | }
176 |
177 | /*
178 | * Dispose of a buffer, by name.
179 | * Ask for the name. Look it up (don't get too
180 | * upset if it isn't there at all!). Get quite upset
181 | * if the buffer is being displayed. Clear the buffer (ask
182 | * if the buffer has been changed). Then free the header
183 | * line and the buffer header. Bound to "C-X K".
184 | */
185 | int killbuffer(bool f, int n)
186 | {
187 | BUFFER *bp;
188 | int s;
189 | string bufn;
190 |
191 | if ((s=mlreply("Kill buffer: ", null, bufn)) != TRUE)
192 | return (s);
193 | if ((bp=buffer_find(bufn, FALSE, 0)) == null) /* Easy if unknown. */
194 | return (TRUE);
195 | return buffer_remove(bp);
196 | }
197 |
198 | /**********************
199 | * Remove buffer bp.
200 | * Returns:
201 | * 0 failed
202 | * !=0 succeeded
203 | */
204 |
205 | int buffer_remove(BUFFER* bp)
206 | {
207 | if (bp.b_nwnd != 0) { /* Error if on screen. */
208 | mlwrite("Buffer is being displayed");
209 | return (FALSE);
210 | }
211 | if (!buffer_clear(bp)) /* Blow text away */
212 | return FALSE;
213 |
214 | //delete bp.b_linep; /* Release header line. */
215 | core.memory.GC.free(bp.b_linep);
216 |
217 | foreach (i, b; buffers)
218 | {
219 | if (b == bp)
220 | {
221 | buffers[i .. $ - 1] = buffers[i + 1 .. $];
222 | buffers = buffers[0 .. $ - 1];
223 | break;
224 | }
225 | }
226 |
227 | //delete bp; /* Release buffer block */
228 | core.memory.GC.free(bp);
229 |
230 | return (TRUE);
231 | }
232 |
233 | /*
234 | * List all of the active
235 | * buffers. First update the special
236 | * buffer that holds the list. Next make
237 | * sure at least 1 window is displaying the
238 | * buffer list, splitting the screen if this
239 | * is what it takes. Lastly, repaint all of
240 | * the windows that are displaying the
241 | * list. Bound to "C-X C-B".
242 | */
243 | int listbuffers(bool f, int n)
244 | {
245 | BUFFER *bp;
246 | int s;
247 |
248 | if ((s=makelist()) != TRUE)
249 | return (s);
250 | if (blistp.b_nwnd == 0) { /* Not on screen yet. */
251 | WINDOW *wp;
252 | if ((wp=wpopup()) == null)
253 | return (FALSE);
254 | bp = wp.w_bufp;
255 | if (--bp.b_nwnd == 0) {
256 | bp.b_dotp = wp.w_dotp;
257 | bp.b_doto = wp.w_doto;
258 | bp.b_markp = wp.w_markp;
259 | bp.b_marko = wp.w_marko;
260 | }
261 | wp.w_bufp = blistp;
262 | ++blistp.b_nwnd;
263 | }
264 | foreach (wp; windows)
265 | {
266 | if (wp.w_bufp == blistp) {
267 | wp.w_linep = lforw(blistp.b_linep);
268 | wp.w_dotp = lforw(blistp.b_linep);
269 | wp.w_doto = 0;
270 | wp.w_markp = null;
271 | wp.w_marko = 0;
272 | wp.w_flag |= WFMODE|WFHARD;
273 | }
274 | }
275 | return (TRUE);
276 | }
277 |
278 | /*
279 | * This routine rebuilds the
280 | * text in the special secret buffer
281 | * that holds the buffer list. It is called
282 | * by the list buffers command. Return TRUE
283 | * if everything works. Return FALSE if there
284 | * is an error (if there is no memory).
285 | */
286 | int makelist()
287 | {
288 | LINE *lp;
289 | int nbytes;
290 | int s;
291 | int type;
292 | char[6+1] b;
293 | char[128] line;
294 |
295 | blistp.b_flag &= ~BFCHG; /* Don't complain! */
296 | if ((s=buffer_clear(blistp)) != TRUE) /* Blow old text away */
297 | return (s);
298 | blistp.b_fname = null;
299 | if (addline("C Size Buffer File") == FALSE
300 | || addline("- ---- ------ ----") == FALSE)
301 | return (FALSE);
302 | /* For all buffers */
303 | foreach (bp; buffers)
304 | {
305 | if ((bp.b_flag&BFTEMP) != 0) { /* Skip magic ones. */
306 | continue;
307 | }
308 | int i = 0; /* Start at left edge */
309 | if ((bp.b_flag&BFCHG) != 0) /* "*" if changed */
310 | line[i++] = '*';
311 | else
312 | line[i++] = ' ';
313 | line[i++] = ' '; /* Gap. */
314 | nbytes = 0; /* Count bytes in buf. */
315 | lp = lforw(bp.b_linep);
316 | while (lp != bp.b_linep) {
317 | nbytes += llength(lp)+1;
318 | lp = lforw(lp);
319 | }
320 | buffer_itoa(b, 6, nbytes); /* 6 digit buffer size. */
321 | line[i .. i + b.length] = b;
322 | i += b.length;
323 | line[i++] = ' '; /* Gap. */
324 | line[i .. i + bp.b_bname.length] = bp.b_bname; // buffer name
325 | i += bp.b_bname.length;
326 | if (bp.b_fname.length)
327 | {
328 | while (i < 25)
329 | line[i++] = ' ';
330 | line[i++] = ' ';
331 | foreach (c; bp.b_bname)
332 | {
333 | if (i < line.length)
334 | line[i++] = c;
335 | }
336 | }
337 | /* Add to the buffer. */
338 | if (addline(line[0 .. i].idup) == FALSE)
339 | return (FALSE);
340 | }
341 | return (TRUE); /* All done */
342 | }
343 |
344 | void buffer_itoa(char[] buf, int width, int num)
345 | {
346 | buf[width] = 0; /* End of string. */
347 | while (num >= 10) { /* Conditional digits. */
348 | buf[--width] = cast(char)((num%10) + '0');
349 | num /= 10;
350 | }
351 | buf[--width] = cast(char)(num + '0'); // Always 1 digit.
352 | while (width != 0) /* Pad with blanks. */
353 | buf[--width] = ' ';
354 | }
355 |
356 | /*
357 | * The argument "text" points to
358 | * a string. Append this line to the
359 | * buffer list buffer. Handcraft the EOL
360 | * on the end. Return TRUE if it worked and
361 | * FALSE if you ran out of room.
362 | */
363 | int addline(string text)
364 | {
365 | LINE *lp;
366 |
367 | if ((lp=line_realloc(null, cast(int)text.length)) == null)
368 | return (FALSE);
369 | for (int i=0; i sbbuf.length)
207 | {
208 | sb = cast(CHAR_INFO *)alloca(numcols * CHAR_INFO.sizeof);
209 | }
210 | for (col = 0; col < numcols; col++)
211 | {
212 | auto c = buffer[col].chr;
213 | sb[col].UnicodeChar = cast(WCHAR)c;
214 | sb[col].Attributes = buffer[col].attr;
215 | if (c >= 0x10000)
216 | {
217 | /* Calculate surrogate pairs, but don't know yet how they
218 | * work, if at all, with WriteConsoleOutput()
219 | */
220 | auto c0 = cast(wchar)((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
221 | auto c1 = cast(wchar)(((c - 0x10000) & 0x3FF) + 0xDC00);
222 | }
223 | //printf("col = %2d, x%2x, '%c'\n",col,sb[col].AsciiChar,sb[col].AsciiChar);
224 | }
225 | if (!WriteConsoleOutputW(cast(HANDLE)disp_state.handle,sb,sbsize,sbcoord,&sdrect))
226 | {
227 | // error
228 | }
229 | physical[] = buffer[];
230 | }
231 |
232 | /*********************************
233 | */
234 |
235 | extern (C) int msm_init()
236 | {
237 | return GetSystemMetrics(SM_MOUSEPRESENT);
238 | }
239 |
240 | extern (C)
241 | {
242 | void msm_term() { }
243 | void msm_showcursor() { }
244 | void msm_hidecursor() { }
245 | }
246 |
247 | struct msm_status // current state of mouse
248 | {
249 | uint row;
250 | uint col;
251 | int buttons;
252 | }
253 |
254 | msm_status mstat;
255 |
256 | /*************************
257 | * Fold MOUSE_EVENT into mstat.
258 | */
259 |
260 | static void mstat_update(MOUSE_EVENT_RECORD *pme)
261 | {
262 | mstat.row = pme.dwMousePosition.Y;
263 | mstat.col = pme.dwMousePosition.X;
264 | mstat.buttons = pme.dwButtonState & 3;
265 | }
266 |
267 | extern (C) int msm_getstatus(uint *pcol,uint *prow)
268 | {
269 | INPUT_RECORD buf;
270 | DWORD cNumRead;
271 |
272 | if (lookahead)
273 | { buf = lookaheadir;
274 | cNumRead = 1;
275 | }
276 | else if (!PeekConsoleInputA(hStdin,&buf,1,&cNumRead))
277 | goto Lret;
278 |
279 | if (cNumRead)
280 | switch (buf.EventType)
281 | {
282 | case MOUSE_EVENT:
283 | mstat_update(&buf.MouseEvent);
284 | goto default;
285 |
286 | default:
287 | Ldiscard:
288 | if (lookahead)
289 | lookahead = 0;
290 | else
291 | ReadConsoleInputA(hStdin,&buf,1,&cNumRead); // discard
292 | break;
293 |
294 | case KEY_EVENT:
295 | if (mstat.buttons & 3)
296 | goto Ldiscard;
297 | break;
298 | }
299 |
300 | Lret:
301 | *prow = mstat.row;
302 | *pcol = mstat.col;
303 | return mstat.buttons;
304 | }
305 |
306 | /*************************************
307 | * Translate key from WIN32 to IBM PC style.
308 | * Params:
309 | * pkey = pointer to key data
310 | * Returns:
311 | * 0 if ignore it
312 | * References:
313 | * https://github.com/dlang/druntime/blob/master/src/core/sys/windows/wincon.d
314 | */
315 |
316 | static uint win32_keytran(KEY_EVENT_RECORD *pkey)
317 | {
318 | if (!pkey.bKeyDown)
319 | return 0; // ignore button up events
320 | uint c = pkey.UnicodeChar;
321 | /+
322 | printf("RepeatCount %x VirtualKeyCode %x VirtualScanCode %x UnicodeChar %x AsciiChar %x ControlKeyState %x\n",
323 | pkey.wRepeatCount, pkey.wVirtualKeyCode, pkey.wVirtualScanCode, pkey.UnicodeChar, pkey.AsciiChar,
324 | pkey.dwControlKeyState);
325 | +/
326 | if (c == 0)
327 | {
328 | switch (pkey.wVirtualScanCode)
329 | {
330 | case 0x1D: // Ctrl
331 | case 0x38: // Alt
332 | case 0x2A: // Left Shift
333 | case 0x36: // Right Shift
334 | break; // ignore
335 | default:
336 | c = (pkey.wVirtualScanCode << 8) & 0xFF00;
337 | if (pkey.dwControlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
338 | {
339 | switch (c)
340 | { case 0x4700: c = 0x7700; break; // Home
341 | case 0x4F00: c = 0x7500; break; // End
342 | case 0x4900: c = 0x8400; break; // PgUp
343 | case 0x5100: c = 0x7600; break; // PgDn
344 | default: c = 0; break;
345 | }
346 | }
347 | break;
348 | }
349 | }
350 | else if (pkey.dwControlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
351 | {
352 | c = (pkey.wVirtualScanCode << 8) & 0xFF00;
353 | }
354 | Lret:
355 | return c;
356 | }
357 |
358 | /**************************
359 | * Return when there are unread chars ready in the input.
360 | */
361 |
362 | void ttwaitkeys()
363 | {
364 | }
365 |
366 | /*************************************
367 | * Wait for any input (yield to other processes).
368 | */
369 |
370 | void ttyield()
371 | {
372 | if (!lookahead)
373 | {
374 | DWORD cNumRead;
375 |
376 | if (!ReadConsoleInputA(hStdin,&lookaheadir,1,&cNumRead))
377 | { printf("readconsoleinput\n");
378 | goto Lret;
379 | }
380 | }
381 | lookahead = 1;
382 | Lret: ;
383 | }
384 |
385 | /*************************************
386 | */
387 |
388 | int ttkeysininput()
389 | {
390 | INPUT_RECORD buf;
391 | DWORD cNumRead;
392 |
393 | if (lookahead)
394 | { buf = lookaheadir;
395 | cNumRead = 1;
396 | }
397 | else if (!PeekConsoleInputA(hStdin,&buf,1,&cNumRead))
398 | goto Lret;
399 |
400 | if (cNumRead)
401 | {
402 | switch (buf.EventType)
403 | {
404 | case MOUSE_EVENT:
405 | mstat_update(&buf.MouseEvent);
406 | goto default;
407 |
408 | default:
409 | Ldiscard:
410 | if (lookahead)
411 | lookahead = 0;
412 | else
413 | ReadConsoleInputA(hStdin,&buf,1,&cNumRead); // discard
414 | cNumRead = 0;
415 | break;
416 |
417 | case KEY_EVENT:
418 | if (!win32_keytran(&buf.KeyEvent))
419 | goto Ldiscard;
420 | break;
421 | }
422 | }
423 |
424 | Lret:
425 | return cNumRead != 0;
426 | }
427 |
428 | extern (C) void popen() { assert(0); }
429 |
430 | void setClipboard(const(char)[] s)
431 | {
432 | if (OpenClipboard(null))
433 | {
434 | EmptyClipboard();
435 |
436 | HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE, (s.length + 1) * char.sizeof);
437 | if (hmem)
438 | {
439 | auto p = cast(char*)GlobalLock(hmem);
440 | memcpy(p, s.ptr, s.length * char.sizeof);
441 | p[s.length] = 0;
442 | GlobalUnlock(hmem);
443 |
444 | SetClipboardData(CF_TEXT, hmem);
445 | }
446 | CloseClipboard();
447 | }
448 | }
449 |
450 | char[] getClipboard()
451 | {
452 | char[] s = null;
453 | if (IsClipboardFormatAvailable(CF_TEXT) &&
454 | OpenClipboard(null))
455 | {
456 | HANDLE h = GetClipboardData(CF_TEXT); // CF_UNICODETEXT is UTF-16
457 | if (h)
458 | {
459 | auto p = cast(char*)GlobalLock(h);
460 | if (p)
461 | {
462 | size_t length = strlen(p);
463 | s = p[0 .. length].dup;
464 | }
465 | GlobalUnlock(h);
466 | }
467 | CloseClipboard();
468 | }
469 | return s;
470 | }
471 |
472 | /***********************
473 | * Open browser on help file.
474 | */
475 |
476 | int help(bool f, int n)
477 | {
478 | printf("\nhelp \n");
479 | char[MAX_PATH + 1] resolved_name = void;
480 | if (GetModuleFileNameA(NULL, resolved_name.ptr, MAX_PATH + 1))
481 | {
482 | size_t len = strlen(resolved_name.ptr);
483 | size_t i;
484 | for (i = len; i; --i)
485 | {
486 | if (resolved_name[i] == '/' ||
487 | resolved_name[i] == '\\' ||
488 | resolved_name[i] == ':')
489 | {
490 | ++i;
491 | break;
492 | }
493 | }
494 | immutable(char)[7] doc = "me.html";
495 | if (i + doc.sizeof <= MAX_PATH)
496 | {
497 | import std.process;
498 | memcpy(resolved_name.ptr + i, doc.ptr, doc.sizeof);
499 | printf("\nhelp2 '%.*s'\n", cast(int)(i + doc.sizeof), resolved_name.ptr);
500 | browse(cast(string)resolved_name[0 .. i + doc.sizeof]);
501 | }
502 | }
503 | return ed.FALSE;
504 | }
505 |
506 | }
507 | else
508 | {
509 |
510 | import ed;
511 |
512 | /***********************
513 | * Open browser on help file.
514 | */
515 |
516 | int help(bool f, int n)
517 | {
518 | return ed.FALSE;
519 | }
520 |
521 | }
522 |
523 |
--------------------------------------------------------------------------------
/src/med/disp.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 | /* D interface to Digital Mars C/C++ disp package.
11 | * Windows only.
12 | * http://www.digitalmars.com/rtl/disp.html
13 | */
14 |
15 | module disp;
16 |
17 | version (Windows)
18 | {
19 |
20 | extern (C)
21 | {
22 |
23 | struct disp_t
24 | { align(1):
25 | uint numrows;
26 | uint numcols;
27 | uint cursorrow;
28 | uint cursorcol;
29 | ubyte mono;
30 | ubyte snowycga;
31 | ubyte mode;
32 | ubyte inited;
33 | ubyte ega;
34 | ubyte[3] reserved;
35 | short nowrap;
36 |
37 | union
38 | {
39 | ushort *base;
40 | struct
41 | { uint offset;
42 | ushort basep;
43 | }
44 | }
45 | void *handle;
46 | }
47 |
48 | extern __gshared disp_t disp_state;
49 |
50 | int disp_printf(char *,...);
51 | int disp_getmode();
52 | int disp_getattr();
53 | int disp_putc(int);
54 | void disp_levelblockpoke(int,int,int,int,uint,uint *,uint,uint *,uint);
55 | void disp_open();
56 | void disp_puts(const char *);
57 | void disp_box(int,int,uint,uint,uint,uint);
58 | void disp_close();
59 | void disp_move(int,int);
60 | void disp_flush();
61 | void disp_eeol();
62 | void disp_eeop();
63 | void disp_startstand();
64 | void disp_endstand();
65 | void disp_setattr(int);
66 | void disp_setcursortype(int);
67 | void disp_pokew(int,int,ushort);
68 | void disp_scroll(int,uint,uint,uint,uint,uint);
69 | void disp_setmode(ubyte);
70 | void disp_peekbox(ushort *,uint,uint,uint,uint);
71 | void disp_pokebox(ushort *,uint,uint,uint,uint);
72 | void disp_fillbox(uint,uint,uint,uint,uint);
73 | void disp_hidecursor();
74 | void disp_showcursor();
75 | ushort disp_peekw(int,int);
76 |
77 | enum
78 | {
79 | DISP_REVERSEVIDEO = 0x70,
80 | DISP_NORMAL = 0x07,
81 | DISP_UNDERLINE = 0x01,
82 | DISP_NONDISPLAY = 0x00,
83 |
84 | DISP_INTENSITY = 0x08,
85 | DISP_BLINK = 0x80,
86 |
87 | DISP_CURSORBLOCK = 100,
88 | DISP_CURSORHALF = 50,
89 | DISP_CURSORUL = 20,
90 | }
91 |
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/src/med/disprev.d:
--------------------------------------------------------------------------------
1 |
2 | immutable string VERSION = "3 Digital Mars";
3 | immutable string EMACSREV = " med." ~ VERSION;
4 |
--------------------------------------------------------------------------------
/src/med/ed.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 |
11 | /*
12 | * This file is the general header file for all parts of the MicroEMACS
13 | * display editor. It contains definitions used by everyone, and it contains
14 | * the stuff you have to edit to create a version of the editor for a specific
15 | * operating system and terminal.
16 | */
17 |
18 | module ed;
19 |
20 | alias ubyte attr_t;
21 |
22 | struct attchar_t
23 | {
24 | dchar chr;
25 | attr_t attr;
26 | }
27 |
28 | enum
29 | {
30 | CVMVAS = 1, /* C-V, M-V arg. in screens. */
31 |
32 | HUGE = 1000, /* Huge number */
33 |
34 | AGRAVE = 0x60, /* M- prefix, Grave (LK201) */
35 | METACH = 0x1B, /* M- prefix, Control-[, ESC */
36 | CTMECH = 0x1C, /* C-M- prefix, Control-\ */
37 | EXITCH = 0x1D, /* Exit level, Control-] */
38 | CTRLCH = 0x1E, /* C- prefix, Control-^ */
39 | HELPCH = 0x1F, /* Help key, Control-_ */
40 | }
41 |
42 | enum MOUSEKEY = 0x12345678; // left mouse button down
43 | enum MOUSEKEYR = 0x12345679; // right mouse button down
44 | enum MOUSEKEYU = 0x7600; // right or left mouse button up
45 |
46 |
47 | enum
48 | {
49 | UPKEY = 0x4800, /* Up arrow key */
50 | DNKEY = 0x5000, /* Down arrow key */
51 | RTKEY = 0x4D00, /* Right arrow key */
52 | LTKEY = 0x4B00, /* Left arrow key */
53 | F1KEY = 0x3B00,
54 | F2KEY = 0x3C00,
55 | F3KEY = 0x3D00,
56 | F4KEY = 0x3E00,
57 | F5KEY = 0x3F00,
58 | F6KEY = 0x4000,
59 | F7KEY = 0x4100,
60 | F8KEY = 0x4200,
61 | F9KEY = 0x4300,
62 | F10KEY = 0x4400,
63 | F11KEY = 0x5700,
64 | F12KEY = 0x5800,
65 | AltF1KEY = 0x6800,
66 | AltF2KEY = 0x6900,
67 | AltF3KEY = 0x6A00,
68 | AltF4KEY = 0x6B00,
69 | AltF5KEY = 0x6C00,
70 | AltF6KEY = 0x6D00,
71 | AltF7KEY = 0x6E00,
72 | AltF8KEY = 0x6F00,
73 | AltF9KEY = 0x7000,
74 | AltF10KEY = 0x7100,
75 | ALTB = 0x3000,
76 | ALTC = 0x2E00,
77 | ALTD = 0x2000,
78 | ALTE = 0x1200,
79 | ALTF = 0x2100,
80 | ALTH = 0x2300,
81 | ALTM = 0x3200,
82 | ALTX = 0x2D00,
83 | ALTZ = 0x2C00,
84 | InsKEY = 0x5200,
85 | CtrlHome = 0x7700,
86 | CtrlEnd = 0x7500,
87 | DelKEY = 0x5300,
88 | CtrlRTKEY = 0x7400,
89 | CtrlLFKEY = 0x7300,
90 | HOMEKEY = 0x4700,
91 | ENDKEY = 0x4F00,
92 | PgUpKEY = 0x4900,
93 | PgDnKEY = 0x5100,
94 |
95 | GOLDKEY = ALTF,
96 | MENU_BUTTON = ALTH,
97 | }
98 |
99 |
100 | char CTRL(char c) { return c & 0x1F; } /* Control flag, or'ed in */
101 |
102 | enum
103 | {
104 | META = METACH, /* Meta flag, or'ed in */
105 | CTLX = CTRL('X'), /* ^X flag, or'ed in */
106 | GOLD = GOLDKEY, /* Another Meta flag, or'ed in */
107 | }
108 |
109 | enum
110 | {
111 | FALSE = 0, /* False, no, bad, etc. */
112 | TRUE = 1, /* True, yes, good, etc. */
113 | ABORT = 2, /* Death, ^G, abort, etc. */
114 | }
115 |
116 | enum
117 | {
118 | CFCPCN = 0x0001, /* Last command was C-P, C-N */
119 | CFKILL = 0x0002, /* Last command was a kill */
120 | }
121 |
122 | /*
123 | * Seperate kbufp[] buffers for cut, word, line and char deletes...
124 | */
125 | enum
126 | { DCUTBUF,
127 | DLINEBUF,
128 | DWORDBUF,
129 | DCHARBUF,
130 | DSPECBUF, /* maximum number of temp buffers */
131 | }
132 |
133 | /*
134 | * State of the syntax highlighting
135 | */
136 | enum Syntax
137 | {
138 | normal,
139 | keyword,
140 | string,
141 | comment,
142 | singleString,
143 | backtickString,
144 | }
145 |
146 | struct SyntaxState
147 | {
148 | Syntax syntax = Syntax.normal;
149 | int nest; // nest level for nested comments like /+ /+ +/ +/
150 | }
151 |
152 | /********************************
153 | * All configuration parameters are stored in this struct.
154 | */
155 |
156 | struct CONFIG
157 | {
158 | attr_t modeattr; /* for mode line */
159 | attr_t normattr; /* for normal text */
160 | attr_t eolattr; /* for end of line */
161 | attr_t markattr; /* for selected text */
162 | char tabchar; /* char to use for tab display */
163 | attr_t urlattr; // for URLs
164 | attr_t searchattr; // for search matches
165 |
166 | // for syntax highlighting
167 | attr_t keyword;
168 | attr_t string;
169 | attr_t comment;
170 | }
171 |
172 | enum Color : attr_t
173 | {
174 | // text colors
175 | black = 0,
176 | red = 1,
177 | green = 2,
178 | yellow = red | green,
179 | blue = 4,
180 | magenta = red | blue, // purple
181 | cyan = green | blue,
182 | lightGray = red | green | blue,
183 |
184 | darkGray = bold | black,
185 | lightRed = bold | red,
186 | lightGreen = bold | green,
187 | lightBlue = bold | blue,
188 | lightYellow = bold | yellow,
189 | lightMagenta = bold | magenta,
190 | lightCyan = bold | cyan,
191 | white = bold | lightGray,
192 |
193 | // background text colors
194 | bgBlack = black << 4,
195 | bgRed = red << 4,
196 | bgGreen = green << 4,
197 | bgYellow = yellow << 4,
198 | bgBlue = blue << 4,
199 | bgMagenta = magenta << 4,
200 | bgCyan = cyan << 4,
201 | bgGray = lightGray << 4,
202 |
203 | bgMask = 0x70,
204 |
205 | bold = 8, // bold only modifies text color by lightening it
206 | underline = 0x80,
207 | reverse = white,
208 | }
209 |
210 |
211 | /**************
212 | * George M. Jones {cbosgd,ihnp4}!osu-eddie!george
213 | * Work Phone: george@ohio-state.csnet
214 | * (614) 457-8600 CompuServe: 70003,2443
215 | */
216 |
217 |
--------------------------------------------------------------------------------
/src/med/file.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 | /*
11 | * The routines in this file
12 | * handle the reading and writing of
13 | * disk files. All of details about the
14 | * reading and writing of the disk are
15 | * in "fileio.c".
16 | */
17 |
18 | module file;
19 |
20 | import core.stdc.stdlib;
21 |
22 | import std.stdio;
23 | import std.path;
24 | import std.string;
25 | import std.utf;
26 | import std.file;
27 |
28 | import ed;
29 | import main;
30 | import region;
31 | import window;
32 | import fileio;
33 | import line;
34 | import buffer;
35 | import display;
36 | import random;
37 |
38 | /**********************************
39 | * Save current file. Get next file and read it into the
40 | * current buffer. Next file is either:
41 | * o next argument from command line
42 | * o input from the user
43 | */
44 |
45 | int filenext(bool f, int n)
46 | { int s;
47 |
48 | if (filesave(f,n) == FALSE) /* save current file */
49 | return FALSE;
50 | if (gargi < gargs.length) /* if more files on command line */
51 | {
52 | s = readin(gargs[gargi]);
53 | gargi++;
54 | }
55 | else /* get file name from user */
56 | s = fileread(f,n);
57 | curbp.b_bname = makename(curbp.b_fname);
58 | return s;
59 | }
60 |
61 | /**********************************
62 | * Insert a file into the current buffer.
63 | */
64 |
65 | int Dinsertfile(bool f, int n)
66 | {
67 | string fnamed;
68 |
69 | if (mlreply("Insert file: ", null, fnamed) == FALSE)
70 | return FALSE;
71 |
72 | string fname = toUTF8(fnamed);
73 | try
74 | {
75 | fname = std.path.expandTilde(fname);
76 | auto fp = File(fname);
77 | mlwrite("[Reading file]");
78 | int nline = 0;
79 | char[] line;
80 | size_t s;
81 | while ((s = fp.readln(line)) != 0)
82 | {
83 | foreach(char c; line)
84 | {
85 | if (c == '\r' || c == '\n')
86 | break;
87 | if (line_insert(1,c) == FALSE)
88 | return FALSE;
89 | }
90 | if (random_newline(FALSE,1) == FALSE)
91 | return FALSE;
92 | ++nline;
93 | }
94 | fp.close();
95 | if (nline == 1)
96 | mlwrite("[Read 1 line]");
97 | else
98 | mlwrite("[Read %d lines]", nline);
99 | return TRUE;
100 | }
101 | catch (Exception e)
102 | {
103 | mlwrite(e.toString());
104 | return FALSE;
105 | }
106 | finally
107 | {
108 | foreach (wp; windows)
109 | {
110 | if (wp.w_bufp == curbp) {
111 | wp.w_flag |= WFMODE|WFHARD;
112 | }
113 | }
114 | }
115 | }
116 |
117 | /*
118 | * Read a file into the current
119 | * buffer. This is really easy; all you do it
120 | * find the name of the file, and call the standard
121 | * "read a file into the current buffer" code.
122 | * Bound to "C-X C-R".
123 | */
124 | int fileread(bool f, int n)
125 | {
126 | int s;
127 | string fname;
128 |
129 | if ((s=mlreply("Read file: ", null, fname)) != TRUE)
130 | return (s);
131 | return (readin(fname));
132 | }
133 |
134 | /*
135 | * Select a file for editing.
136 | * Look around to see if you can find the
137 | * file in another buffer; if you can find it
138 | * just switch to the buffer. If you cannot find
139 | * the file, create a new buffer, read in the
140 | * text, and switch to the new buffer.
141 | * Bound to GOLD E.
142 | */
143 | int filevisit(bool f, int n)
144 | {
145 | string fname;
146 |
147 | return mlreply("Visit file: ", null, fname) &&
148 | window_split(f,n) &&
149 | file_readin(fname);
150 | }
151 |
152 | int file_readin(string fname)
153 | {
154 | LINE *lp;
155 | int i;
156 | int s;
157 | string bname;
158 |
159 | /* If there is an existing buffer with the same file name, simply */
160 | /* switch to it instead of reading the file again. */
161 | foreach (bp; buffers)
162 | {
163 | /* Always redo temporary buffers, check for filename match. */
164 | if ((bp.b_flag&BFTEMP)==0 && globMatch(bp.b_fname, fname))
165 | {
166 | /* If the current buffer now becomes undisplayed */
167 | if (--curbp.b_nwnd == 0)
168 | {
169 | curbp.b_dotp = curwp.w_dotp;
170 | curbp.b_doto = curwp.w_doto;
171 | curbp.b_markp = curwp.w_markp;
172 | curbp.b_marko = curwp.w_marko;
173 | }
174 | curbp = bp;
175 | curwp.w_bufp = bp;
176 | if (bp.b_nwnd++ == 0) /* if buffer not already displayed */
177 | {
178 | curwp.w_dotp = bp.b_dotp;
179 | curwp.w_doto = bp.b_doto;
180 | curwp.w_markp = bp.b_markp;
181 | curwp.w_marko = bp.b_marko;
182 | }
183 | else
184 | {
185 | /* Set dot to be at place where other window has it */
186 | foreach (wp; windows)
187 | {
188 | if (wp!=curwp && wp.w_bufp==bp)
189 | {
190 | curwp.w_dotp = wp.w_dotp;
191 | curwp.w_doto = wp.w_doto;
192 | curwp.w_markp = wp.w_markp;
193 | curwp.w_marko = wp.w_marko;
194 | break;
195 | }
196 | }
197 | }
198 |
199 | /* Adjust frame so dot is at center */
200 | lp = curwp.w_dotp;
201 | i = curwp.w_ntrows/2;
202 | while (i-- && lback(lp)!=curbp.b_linep)
203 | lp = lback(lp);
204 | curwp.w_linep = lp;
205 |
206 | curwp.w_flag |= WFMODE|WFHARD;
207 | mlwrite("[Old buffer]");
208 | return TRUE;
209 | }
210 | }
211 |
212 | bname = makename(fname); /* New buffer name. */
213 | BUFFER* bp;
214 | while ((bp=buffer_find(bname, FALSE, 0)) != null)
215 | {
216 | s = mlreply("Buffer name: ", null, bname);
217 | if (s == ABORT) /* ^G to just quit */
218 | return (s);
219 | if (s == FALSE) { /* CR to clobber it */
220 | bname = makename(fname);
221 | break;
222 | }
223 | }
224 | if (bp==null && (bp=buffer_find(bname, TRUE, 0))==null)
225 | { mlwrite("Cannot create buffer");
226 | return (FALSE);
227 | }
228 | if (--curbp.b_nwnd == 0) /* Undisplay */
229 | { curbp.b_dotp = curwp.w_dotp;
230 | curbp.b_doto = curwp.w_doto;
231 | curbp.b_markp = curwp.w_markp;
232 | curbp.b_marko = curwp.w_marko;
233 | }
234 | curbp = bp; /* Switch to it. */
235 | curwp.w_bufp = bp;
236 | curbp.b_nwnd++;
237 | return (readin(fname)); /* Read it in. */
238 | }
239 |
240 | /*
241 | * Read file "fname" into the current
242 | * buffer, blowing away any text found there. Called
243 | * by both the read and visit commands. Return the final
244 | * status of the read. Also called by the mainline,
245 | * to read in a file specified on the command line as
246 | * an argument.
247 | */
248 | int readin(string dfname)
249 | {
250 | auto bp = curbp; // Cheap.
251 | auto b = buffer_clear(bp); // Might be old.
252 | if (b != TRUE)
253 | return b;
254 | bp.b_flag &= ~(BFTEMP|BFCHG);
255 | bp.setFilename(dfname);
256 |
257 | /* Determine if file is read-only */
258 | auto fname = std.path.expandTilde(toUTF8(dfname));
259 | if (ffreadonly(fname)) /* is file read-only? */
260 | bp.b_flag |= BFRDONLY;
261 | else
262 | bp.b_flag &= ~BFRDONLY;
263 |
264 | try
265 | {
266 | if (!std.file.exists(fname))
267 | {
268 | mlwrite("[New file]");
269 | return TRUE;
270 | }
271 | auto fp = File(fname);
272 | mlwrite("[Reading file]");
273 | int nline = 0;
274 | char[] line;
275 | size_t s;
276 | bool first = true;
277 | while ((s = fp.readln(line)) != 0)
278 | {
279 | if (line.length && line[$ - 1] == '\n')
280 | line = line[0 .. $ - 1];
281 | if (line.length && line[$ - 1] == '\r')
282 | line = line[0 .. $ - 1];
283 |
284 | LINE *lp1;
285 | LINE *lp2;
286 |
287 | if ((lp1=line_realloc(null,0)) == null) {
288 | s = FIOERR; /* Keep message on the */
289 | break; /* display. */
290 | }
291 | lp2 = lback(curbp.b_linep);
292 | lp2.l_fp = lp1;
293 | lp1.l_fp = curbp.b_linep;
294 | lp1.l_bp = lp2;
295 | curbp.b_linep.l_bp = lp1;
296 | if (first && line.length >= 3 && line[0] == 0xEF && line[1] == 0xBB && line[2] == 0xBF)
297 | line = line[3..$]; // skip BOM
298 | lp1.l_text = line[].dup;
299 |
300 | first = false;
301 | ++nline;
302 | }
303 | fp.close();
304 | if (nline == 1)
305 | mlwrite("[Read 1 line]");
306 | else
307 | mlwrite("[Read %d lines]", nline);
308 | return TRUE;
309 | }
310 | catch (Exception e)
311 | {
312 | mlwrite(e.toString());
313 | return FALSE;
314 | }
315 | finally
316 | {
317 | foreach (wp; windows)
318 | {
319 | if (wp.w_bufp == curbp) {
320 | wp.w_linep = lforw(curbp.b_linep);
321 | wp.w_dotp = lforw(curbp.b_linep);
322 | wp.w_doto = 0;
323 | wp.w_markp = null;
324 | wp.w_marko = 0;
325 | wp.w_flag |= WFMODE|WFHARD;
326 | }
327 | }
328 | }
329 | }
330 |
331 | /*
332 | * Take a file name, and from it
333 | * fabricate a buffer name. This routine knows
334 | * about the syntax of file names on the target system.
335 | * I suppose that this information could be put in
336 | * a better place than a line of code.
337 | */
338 | string makename(string fname)
339 | {
340 | return fname;
341 | }
342 |
343 | /*
344 | * Ask for a file name, and write the
345 | * contents of the current buffer or region to that file.
346 | * Update the remembered file name and clear the
347 | * buffer changed flag. This handling of file names
348 | * is different from the earlier versions, and
349 | * is more compatible with Gosling EMACS than
350 | * with ITS EMACS. Bound to "C-X C-W".
351 | */
352 | int filewrite(bool f, int n)
353 | {
354 | int s;
355 | string fname;
356 |
357 | if ((s=mlreply("Write file: ", null, fname)) != TRUE)
358 | return (s);
359 | if (curwp.w_markp) /* if marking a region */
360 | { REGION region;
361 |
362 | if (!getregion(®ion))
363 | return FALSE;
364 | return file_writeregion(fname,®ion);
365 | }
366 | else
367 | {
368 | if ((s=writeout(fname)) == TRUE) {
369 | curbp.setFilename(fname);
370 | fileunmodify(f,n);
371 | }
372 | }
373 | return (s);
374 | }
375 |
376 | /****************************
377 | * Mark a file as being unmodified.
378 | */
379 |
380 | int fileunmodify(bool f, int n)
381 | {
382 | curbp.b_flag &= ~BFCHG;
383 |
384 | /* Update mode lines. */
385 | foreach (wp; windows)
386 | {
387 | if (wp.w_bufp == curbp)
388 | wp.w_flag |= WFMODE;
389 | }
390 | return TRUE;
391 | }
392 |
393 | /*
394 | * Save the contents of the current
395 | * buffer in its associated file. No nothing
396 | * if nothing has changed (this may be a bug, not a
397 | * feature). Error if there is no remembered file
398 | * name for the buffer. Bound to "C-X C-S". May
399 | * get called by "C-Z".
400 | */
401 | int filesave(bool f, int n)
402 | {
403 | WINDOW *wp;
404 | int s;
405 |
406 | if ((curbp.b_flag&BFCHG) == 0) /* Return, no changes. */
407 | return (TRUE);
408 | if (curbp.b_fname.length == 0) { /* Must have a name. */
409 | mlwrite("No file name");
410 | return (FALSE);
411 | }
412 | if ((s=writeout(curbp.b_fname)) == TRUE) {
413 | fileunmodify(f,n);
414 | }
415 | return (s);
416 | }
417 |
418 | /*
419 | * Save the contents of each and every modified
420 | * buffer. Does nothing if the buffer is temporary
421 | * or has no filename.
422 | */
423 | int filemodify(bool f, int n)
424 | {
425 | int s = TRUE;
426 |
427 | auto oldbp = curbp;
428 | foreach (bp; buffers)
429 | {
430 | curbp = bp;
431 | if((curbp.b_flag&BFCHG) == 0 || /* if no changes */
432 | curbp.b_flag & BFTEMP || /* if temporary */
433 | curbp.b_fname.length == 0) /* Must have a name */
434 | continue;
435 | if((s&=writeout(curbp.b_fname)) == TRUE )
436 | fileunmodify(f,n);
437 | }
438 | curbp = oldbp;
439 | return( s );
440 | }
441 |
442 | /*
443 | * This function performs the details of file
444 | * writing. Uses the file management routines in the
445 | * "fileio.c" package. The number of lines written is
446 | * displayed. Sadly, it looks inside a LINE; provide
447 | * a macro for this. Most of the grief is error
448 | * checking of some sort.
449 | */
450 | int writeout(string dfn)
451 | {
452 | auto fn = std.path.expandTilde(toUTF8(dfn));
453 | /*
454 | * Supply backups when writing files.
455 | */
456 | version (Windows)
457 | {
458 | auto backupname = std.path.setExtension(fn, "bak");
459 | }
460 | else
461 | {
462 | auto backupname = buildPath(dirName(fn), baseName(fn) ~ "~");
463 | }
464 |
465 | try
466 | {
467 | std.file.remove(backupname); // Remove old backup file
468 | }
469 | catch (Throwable o)
470 | {
471 | }
472 |
473 | if (ffrename(fn, backupname) != FIOSUC)
474 | return FALSE; // Make new backup file
475 |
476 | try
477 | {
478 | auto f = File(fn, "w");
479 |
480 | if ( ffchmod( fn, backupname ) != FIOSUC ) /* Set protection */
481 | { f.close();
482 | return( FALSE );
483 | }
484 |
485 | auto lp = lforw(curbp.b_linep); // First line.
486 | int nline = 0; // Number of lines.
487 | while (lp != curbp.b_linep) {
488 | f.writeln(toUTF8(lp.l_text[0 .. llength(lp)]));
489 | ++nline;
490 | lp = lforw(lp);
491 | }
492 |
493 | f.close();
494 | if (nline == 1)
495 | mlwrite("[Wrote 1 line]");
496 | else
497 | mlwrite("[Wrote %d lines]", nline);
498 | return TRUE;
499 | }
500 | catch (Exception e)
501 | {
502 | mlwrite(e.toString());
503 | return FALSE;
504 | }
505 | }
506 |
507 | /*
508 | * The command allows the user
509 | * to modify the file name associated with
510 | * the current buffer. It is like the "f" command
511 | * in UNIX "ed". The operation is simple; just zap
512 | * the name in the BUFFER structure, and mark the windows
513 | * as needing an update. You can type a blank line at the
514 | * prompt if you wish.
515 | */
516 | int filename(bool f, int n)
517 | {
518 | int s;
519 | string fname;
520 |
521 | if ((s=mlreply("New File Name: ", null, fname)) == ABORT)
522 | return (s);
523 | curbp.setFilename( s == FALSE ? null : fname);
524 | foreach (wp; windows)
525 | { // Update mode lines.
526 | if (wp.w_bufp == curbp)
527 | wp.w_flag |= WFMODE;
528 | }
529 | return (TRUE);
530 | }
531 |
532 | /*******************************
533 | * Write region out to file.
534 | */
535 |
536 | int file_writeregion(string dfilename, REGION* region)
537 | {
538 | auto lp = region.r_linep; /* First line. */
539 | auto loffs = region.r_offset;
540 | auto size = region.r_size;
541 | int nline = 0; /* Number of lines. */
542 |
543 | try
544 | {
545 | auto filename = std.path.expandTilde(toUTF8(dfilename));
546 | auto f = File(filename, "w");
547 | while (size > 0)
548 | {
549 | auto nchars = llength(lp) - loffs;
550 | if (nchars > size) /* if last line is not a full line */
551 | nchars = size;
552 | f.writeln(toUTF8(lp.l_text[loffs .. loffs + nchars]));
553 | size -= nchars + 1;
554 | ++nline;
555 | lp = lforw(lp);
556 | loffs = 0;
557 | }
558 | f.close();
559 | if (nline == 1)
560 | mlwrite("[Wrote 1 line]");
561 | else
562 | mlwrite("[Wrote %d lines]", nline);
563 | return TRUE;
564 | }
565 | catch (Exception e)
566 | {
567 | mlwrite(e.toString());
568 | return FALSE;
569 | }
570 | }
571 |
572 |
--------------------------------------------------------------------------------
/src/med/fileio.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 | /*
11 | * The routines in this file read and write ASCII files from the disk. All of
12 | * the knowledge about files are here. A better message writing scheme should
13 | * be used.
14 | */
15 |
16 | module fileio;
17 |
18 | import core.stdc.stdio;
19 | import core.stdc.stdlib;
20 | import core.stdc.errno;
21 |
22 | import std.file;
23 | import std.path;
24 | import std.string;
25 | import std.stdio;
26 | import std.conv;
27 |
28 | version (Windows)
29 | {
30 | import core.sys.windows.windows;
31 | }
32 |
33 | version (Posix)
34 | {
35 | import core.sys.posix.unistd;
36 | import core.sys.posix.sys.stat;
37 | }
38 |
39 | import ed;
40 | import display;
41 |
42 | enum ENOENT = 2;
43 |
44 | enum
45 | {
46 | FIOSUC = 0, /* File I/O, success. */
47 | FIOFNF = 1, /* File I/O, file not found. */
48 | FIOEOF = 2, /* File I/O, end of file. */
49 | FIOERR = 3, /* File I/O, error. */
50 | }
51 |
52 | /***************************
53 | * Determine if file is read-only.
54 | */
55 |
56 | bool ffreadonly(string name)
57 | {
58 | uint a;
59 | bool exists = true;
60 | try
61 | {
62 | a = std.file.getAttributes(name);
63 | }
64 | catch (Throwable o)
65 | {
66 | exists = false;
67 | }
68 |
69 | version (Win32)
70 | {
71 | return (a & FILE_ATTRIBUTE_READONLY) != 0;
72 | }
73 | else
74 | {
75 | return exists && (a & S_IWUSR) == 0;
76 | }
77 | }
78 |
79 | /*
80 | * Rename a file
81 | */
82 | int ffrename(string from, string to)
83 | {
84 | try
85 | {
86 | from = std.path.expandTilde(from);
87 | to = std.path.expandTilde(to);
88 | version (Posix)
89 | {
90 | stat_t buf;
91 | if( stat( toStringz(from), &buf ) != -1
92 | && !(buf.st_uid == getuid() && (buf.st_mode & octal!200))
93 | && !(buf.st_gid == getgid() && (buf.st_mode & octal!20))
94 | && !( (buf.st_mode & octal!2)) )
95 | {
96 | mlwrite("Cannot open file for writing.");
97 | /* Note the above message is a lie, but because this */
98 | /* routine is only called by the backup file creation */
99 | /* code, the message will look right to the user. */
100 | return( FIOERR );
101 | }
102 | }
103 | rename( from, to );
104 | }
105 | catch (Throwable o)
106 | {
107 | }
108 | return( FIOSUC );
109 | }
110 |
111 |
112 | /*
113 | * Change the protection on a file to match that on file
114 | */
115 | int ffchmod(string subject, string image)
116 | {
117 | version (Posix)
118 | {
119 | subject = std.path.expandTilde(subject);
120 | image = std.path.expandTilde(image);
121 |
122 | uint attr;
123 | try
124 | {
125 | attr = std.file.getAttributes(image);
126 | }
127 | catch (FileException fe)
128 | {
129 | return( FIOSUC );
130 | /* Note that this won't work in all cases, but because */
131 | /* this is only called from the backup file creator, it */
132 | /* will work. UGLY!! */
133 | }
134 | if (chmod( toStringz(subject), attr ) == -1 )
135 | {
136 | mlwrite("Cannot open file for writing.");
137 | /* Note the above message is a lie, but because this */
138 | /* routine is only called by the backup file creation */
139 | /* code, the message will look right to the user. */
140 | return( FIOERR );
141 | }
142 | }
143 | return( FIOSUC );
144 | }
145 |
146 |
--------------------------------------------------------------------------------
/src/med/more.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 |
11 | /*
12 | * Due to my (Bjorn Benson) laziness, the functions will all
13 | * work with a positive argument, but may or may not with
14 | * a negative.
15 | */
16 |
17 | module more;
18 |
19 | import core.stdc.stdio;
20 |
21 | import std.ascii;
22 | import std.uni;
23 | import std.process;
24 |
25 | import ed;
26 | import main;
27 | import window;
28 | import buffer;
29 | import line;
30 | import search;
31 | import random;
32 | import region;
33 | import word;
34 | import basic;
35 | import terminal;
36 | import display;
37 | import url;
38 | import utf;
39 |
40 | version (Posix)
41 | {
42 | import core.sys.posix.signal;
43 | import core.sys.posix.unistd;
44 | }
45 |
46 | /*
47 | * The multiple delete buffers
48 | */
49 | enum
50 | {
51 | DK_CUT,
52 | DK_LINE,
53 | DK_WORD,
54 | DK_CHAR,
55 | }
56 |
57 | void SETMARK()
58 | {
59 | curwp.w_markp = curwp.w_dotp;
60 | curwp.w_marko = curwp.w_doto;
61 | }
62 |
63 | /*
64 | * Current direction that things happen in
65 | */
66 | enum
67 | {
68 | ADVANCE,
69 | BACKUP,
70 | }
71 |
72 | int Dcur_direction = ADVANCE;
73 |
74 | int Dsearch(bool f, int n)
75 | {
76 | if( Dcur_direction == ADVANCE )
77 | return( forwsearch(f, n) );
78 | else return( backsearch(f, n) );
79 | }
80 |
81 | int Dsearchagain(bool f, int n)
82 | {
83 | int s;
84 | Dnoask_search = true;
85 | scope(exit) Dnoask_search = false;
86 | if( Dcur_direction == ADVANCE )
87 | s = forwsearch(f, n);
88 | else s = backsearch(f, n);
89 | return s;
90 | }
91 |
92 | int Ddelline(bool f, int n)
93 | {
94 | int s = true;
95 |
96 | kill_setbuffer(DK_LINE);
97 | kill_freebuffer();
98 | while( n-- > 0 && s )
99 | { curwp.w_doto = 0;
100 | s &= line_delete(llength(curwp.w_dotp) + 1, true);
101 | }
102 | kill_setbuffer(DK_CUT);
103 | return s;
104 | }
105 |
106 | int Dundelline(bool f, int n)
107 | {
108 | int s = true;
109 |
110 | kill_setbuffer(DK_LINE);
111 | while( n-- > 0 && s )
112 | {
113 | curwp.w_doto = 0;
114 | s = random_yank(true, 1);
115 | backline(false, 1);
116 | curwp.w_doto = 0;
117 | }
118 | kill_setbuffer(DK_CUT);
119 | return s;
120 | }
121 |
122 | int Ddelword(bool f, int n)
123 | {
124 | int s = true;
125 |
126 | kill_setbuffer(DK_WORD);
127 | kill_freebuffer();
128 | while( n-- > 0 && s )
129 | {
130 | SETMARK();
131 | s = word_forw(false, 1);
132 | if( !s ) break;
133 | s = region_kill(false, 1);
134 | }
135 | kill_setbuffer(DK_CUT);
136 | return s;
137 | }
138 |
139 | int Ddelbword(bool f, int n)
140 | {
141 | int s = true;
142 |
143 | kill_setbuffer(DK_WORD);
144 | kill_freebuffer();
145 | while( n-- > 0 && s )
146 | {
147 | SETMARK;
148 | s = word_back(false, 1);
149 | if( !s ) break;
150 | s = region_kill(false, 1);
151 | }
152 | kill_setbuffer(DK_CUT);
153 | return s;
154 | }
155 |
156 | int Dundelword(bool f, int n)
157 | {
158 | int s = true;
159 |
160 | kill_setbuffer(DK_WORD);
161 | while( n-- > 0 && s )
162 | s &= random_yank(true, 1);
163 | kill_setbuffer(DK_CUT);
164 | return s;
165 | }
166 |
167 | int Dadvance(bool f, int n)
168 | {
169 | Dcur_direction = ADVANCE;
170 | return true;
171 | }
172 |
173 | int Dbackup(bool f, int n)
174 | {
175 | Dcur_direction = BACKUP;
176 | return true;
177 | }
178 |
179 | int Dignore(bool f, int n)
180 | {
181 | /* Ignore this command. Useful for ^S and ^Q flow control */
182 | /* sent out by some terminals. */
183 | return true;
184 | }
185 |
186 | int Dpause(bool f, int n)
187 | {
188 | version (Posix)
189 | {
190 | term.t_move( term.t_nrow - 1, 0 );
191 | term.t_eeop();
192 | term.t_flush();
193 | term.t_close();
194 | killpg(getpgid(0), 18); /* SIGTSTP -- stop the current program */
195 | term.t_open();
196 | sgarbf = true;
197 | window_refresh(false, 1);
198 | }
199 | return true;
200 | }
201 |
202 | /*********************************
203 | * Decide whether to uppercase a word or a region.
204 | */
205 |
206 | int misc_upper(bool f, int n)
207 | {
208 | if (curwp.w_markp)
209 | return region_upper(f,n);
210 | else
211 | return word_upper(f,n);
212 | }
213 |
214 | /*********************************
215 | * Decide whether to lowercase a word or a region.
216 | */
217 |
218 | int misc_lower(bool f, int n)
219 | {
220 | if (curwp.w_markp)
221 | return region_lower(f,n);
222 | else
223 | return word_lower(f,n);
224 | }
225 |
226 | /*********************************
227 | * Insert file name and date at top of file.
228 | */
229 |
230 | int Dinsertdate(bool f, int n)
231 | { return false;
232 | }
233 |
234 | /***********************************
235 | * Remove trailing whitespace from line.
236 | */
237 |
238 | void deblank()
239 | { int len;
240 | int n;
241 | int c;
242 | int i;
243 |
244 | len = llength(curwp.w_dotp);
245 | for (i = len - 1; i >= 0; i--)
246 | {
247 | c = lgetc(curwp.w_dotp, i);
248 | if (!isSpace(c))
249 | break;
250 | }
251 | n = (len - 1) - i;
252 | if (n)
253 | {
254 | curwp.w_doto = i + 1;
255 | line_delete(n,false);
256 | }
257 | }
258 |
259 | /*********************************
260 | * Convert C comment to C++ comment.
261 | */
262 |
263 | int Dcppcomment(bool f, int n)
264 | {
265 | int c;
266 | int i;
267 | LINE *dotpsave;
268 | int dotosave;
269 |
270 | if (n < 0)
271 | goto err;
272 | if (window_marking(curwp))
273 | { REGION region;
274 | int s;
275 |
276 | if ((s = getregion(®ion)) != true)
277 | return s;
278 | dotpsave = curwp.w_dotp;
279 | dotosave = curwp.w_doto;
280 | curwp.w_dotp = region.r_linep;
281 | curwp.w_doto = region.r_offset;
282 | n = region.r_nlines;
283 | }
284 | while (n--)
285 | { int len;
286 |
287 | deblank();
288 | len = llength(curwp.w_dotp);
289 | if (len)
290 | {
291 | for (i = 0; i + 3 < len; i++)
292 | {
293 | c = lgetc(curwp.w_dotp, i);
294 | if (c == '/' && lgetc(curwp.w_dotp, i + 1) == '*')
295 | {
296 | if (lgetc(curwp.w_dotp, len - 2) == '*' &&
297 | lgetc(curwp.w_dotp, len - 1) == '/')
298 | {
299 | curwp.w_doto = i + 1;
300 | line_delete(1,false);
301 | line_insert(1,'/');
302 | curwp.w_doto = len - 2;
303 | line_delete(2,false);
304 | deblank();
305 | break;
306 | }
307 | }
308 | }
309 | curwp.w_doto = 0; /* move to beginning of line */
310 | }
311 | if (forwline(false,1) == false)
312 | goto err;
313 | }
314 | if (window_marking(curwp))
315 | {
316 | if (dotosave > llength(dotpsave))
317 | dotosave = llength(dotpsave);
318 | curwp.w_dotp = dotpsave;
319 | curwp.w_doto = dotosave;
320 | }
321 | return true;
322 |
323 | err:
324 | return false;
325 | }
326 |
327 | /************************************
328 | * Open browser on URL.
329 | */
330 | int openBrowser(bool f, int n)
331 | {
332 | LINE* dotp = curwp.w_dotp;
333 | auto s = getURL(dotp.l_text[0 .. llength(dotp)], curwp.w_doto);
334 | if (s)
335 | {
336 | browse(cast(string)s);
337 | return TRUE;
338 | }
339 | return FALSE;
340 | }
341 |
342 | /***************************
343 | * Look up current character in the replacement table,
344 | * and replace it with the next character in the table.
345 | * Returns:
346 | * TRUE = success
347 | * FALSE = failure
348 | */
349 |
350 | int scrollUnicode(bool f, int n)
351 | {
352 | /* Mapping table of one character to the next in each entry
353 | */
354 | __gshared immutable string[] table =
355 | [
356 | "a\ä\à\á\â\ã\å\æ\α\ª",
357 | "e\è\é\ê\ë\ε\η",
358 | "i\ì\í\î\ï\ι",
359 | "o\ò\ó\ô\õ\ö\ø\ο\œ",
360 | "u\ù\ú\û\ü\μ\υ",
361 |
362 | "A\À\Á\Â\Ã\Ä\Å\Æ\Α\∀",
363 | "E\È\É\Ê\Ë\Ε\∃\∈\∉\∋",
364 | "I\Ì\Í\Î\Ï\Ι\∫",
365 | "O\Ò\Ó\Ô\Ö\Ο",
366 | "U\Ù\Ú\Û\Ü\∩\∪\⊂\⊃\⊄",
367 |
368 | "c\ç\©",
369 | "C\Ç",
370 |
371 | "$\€\¢\£\¤\¥",
372 | "\"\“\”\„\«\»",
373 | "'\‘\’\‚\´",
374 | "-\–\—\¯\‾\−",
375 | "~\˜\∼\≅\≈",
376 | "!\¡",
377 | ];
378 |
379 | LINE* dotp = curwp.w_dotp;
380 | auto s = dotp.l_text[0 .. llength(dotp)];
381 | size_t index = curwp.w_doto;
382 |
383 | size_t i = index;
384 | dchar dc = decodeUTF8(s, i);
385 | foreach (entry; table)
386 | {
387 | for (size_t j = 0; j < entry.length; )
388 | {
389 | dchar dr = decodeUTF8(entry, j);
390 | if (dr == dc)
391 | {
392 | if (j == entry.length)
393 | j = 0;
394 | size_t k = j;
395 | decodeUTF8(entry, k);
396 |
397 | /* Replace s[index .. i] with entry[j .. k]
398 | */
399 | line_delete(cast(int)(i - index), FALSE);
400 | foreach (char c; entry[j .. k])
401 | line_insert(1, c);
402 | backchar(f, cast(int)(k - j));
403 | line_change(WFEDIT);
404 |
405 | return TRUE;
406 | }
407 | }
408 | }
409 | return FALSE;
410 | }
411 |
--------------------------------------------------------------------------------
/src/med/mouse.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 |
11 | module mouse;
12 |
13 | import disp;
14 | import core.stdc.time;
15 |
16 | import ed;
17 | import window;
18 | import line;
19 | import main;
20 | import terminal;
21 | import display;
22 | import word;
23 |
24 | //#include
25 |
26 | static int clicks = 0; /* number of clicks we've seen */
27 | static clock_t lastclick; /* time of last click */
28 |
29 | /*********************************
30 | * Call this routine in the main command loop.
31 | * It handles any mouse commands.
32 | * Returns:
33 | * 0 no mouse input
34 | * !=0 value is a keystroke
35 | */
36 |
37 | int mouse_command()
38 | { uint x,y;
39 | WINDOW *wp;
40 | LINE *lp;
41 | int status;
42 |
43 | if (!hasmouse) /* if no mouse installed */
44 | return 0;
45 | status = msm_getstatus(&x,&y); /* read button status */
46 | mouse_tocursor(&x,&y); /* collect real cursor coords */
47 | if (status & 1) /* if left button is down */
48 | { int doto;
49 |
50 | mouse_findpos(x,y,&wp,&lp,&doto);
51 | if (wp && lp)
52 | { markcol = wp.w_startcol + x;
53 | mouse_markdrag(wp,lp,doto);
54 | }
55 | else
56 | { if (wp)
57 | {
58 | curbp = wp.w_bufp;
59 | curwp = wp;
60 | /* Examine window action buttons */
61 | switch (x)
62 | { case 0:
63 | window_only(FALSE,1);
64 | goto L2;
65 | case 1:
66 | window_split(FALSE,1);
67 | goto L2;
68 | case 2:
69 | delwind(FALSE,1);
70 | L2: update();
71 | goto L1;
72 | case 3:
73 | do
74 | { window_mvup(FALSE,1);
75 | update();
76 | } while (mouse_leftisdown());
77 | break;
78 | case 4:
79 | do
80 | { window_mvdn(FALSE,1);
81 | update();
82 | } while (mouse_leftisdown());
83 | break;
84 | default:
85 | mouse_windrag(wp);
86 | break;
87 | }
88 | update();
89 | }
90 | else
91 | L1:
92 | while (mouse_leftisdown()) /* wait till button goes up */
93 | { }
94 | clicks = 0;
95 | }
96 | }
97 | else if (status & 2) /* if right button is down */
98 | {
99 | //return memenu_mouse(y,x);
100 | }
101 | return 0;
102 | }
103 |
104 | /*******************************
105 | * Convert from Microsoft coordinates to proper cursor coordinates.
106 | */
107 |
108 | static void mouse_tocursor(uint* px, uint* py)
109 | {
110 | }
111 |
112 | /***************************
113 | * Set cursor at row,col.
114 | */
115 |
116 | static void mouse_findpos(uint col, uint row, WINDOW** p_wp, LINE** p_lp, int* p_doto)
117 | { int r;
118 | int i;
119 | LINE *lp;
120 |
121 | *p_wp = null;
122 | *p_lp = null;
123 | *p_doto = 0; /* default cases */
124 | r = 0; /* starting row for window */
125 | foreach (wp; windows)
126 | {
127 | if (row <= r + wp.w_ntrows)
128 | {
129 | *p_wp = wp;
130 | if (row == r + wp.w_ntrows)
131 | return;
132 | for (lp = wp.w_linep; lp != wp.w_bufp.b_linep; lp = lforw(lp))
133 | { if (row == r)
134 | break;
135 | r++;
136 | }
137 | *p_lp = lp;
138 | /* Determine offset into line corresponding to col */
139 | *p_doto = coltodoto(lp,wp.w_startcol + col);
140 | return;
141 | }
142 | r += wp.w_ntrows + 1;
143 | }
144 | }
145 |
146 | /*****************************
147 | * Given an initial position, drag the mouse, marking
148 | * text as we go.
149 | */
150 |
151 | static void mouse_markdrag(WINDOW* wp, LINE* lp, int doto)
152 | { uint x,y;
153 |
154 | curbp = wp.w_bufp;
155 | curwp = wp;
156 | if (lp != wp.w_dotp) /* if on different line */
157 | { wp.w_dotp = lp;
158 | wp.w_flag |= WFMOVE;
159 | }
160 | wp.w_doto = doto;
161 | wp.w_markp = lp;
162 | wp.w_marko = doto; /* set new mark */
163 | curwp.w_flag |= WFHARD;
164 | update();
165 |
166 | /* Continue marking until button goes up */
167 | while (msm_getstatus(&x,&y) & 1)
168 | {
169 | mouse_tocursor(&x,&y); /* collect real cursor coords */
170 | mouse_findpos(x,y,&wp,&lp,&doto);
171 | if (wp && wp == curwp && lp)
172 | {
173 | if (wp.w_markp || lp != wp.w_dotp) /* if on different line */
174 | {
175 | wp.w_dotp = lp;
176 | wp.w_flag |= WFMOVE;
177 | }
178 | wp.w_doto = doto;
179 | }
180 | else if (!wp ||
181 | wp != curwp && wp.w_toprow > curwp.w_toprow ||
182 | wp == curwp && !lp)
183 | window_mvdn(FALSE,1);
184 | else
185 | window_mvup(FALSE,1);
186 | curgoal = curwp.w_startcol + x;
187 | lastflag |= CFCPCN; /* behave as if forwline() or backline() */
188 | update();
189 | }
190 | /* If mark start and mark end match, then no mark */
191 | if (wp.w_markp == wp.w_dotp &&
192 | wp.w_marko == wp.w_doto)
193 | { clock_t thisclick;
194 |
195 | wp.w_markp = null;
196 | thisclick = clock();
197 | if (clicks)
198 | { if (thisclick - lastclick > 500) //CLOCKS_PER_SEC / 2)
199 | clicks = 0;
200 | }
201 | clicks++;
202 | lastclick = thisclick;
203 |
204 | switch (clicks)
205 | { case 1:
206 | break;
207 | case 2:
208 | word_select(FALSE,1);
209 | goto L1;
210 | case 3:
211 | word_lineselect(FALSE,1);
212 | L1:
213 | mlerase();
214 | update();
215 | break;
216 | default:
217 | clicks = 0;
218 | break;
219 | }
220 | }
221 | else
222 | clicks = 0;
223 | }
224 |
225 | /*****************************
226 | * Given an initial position, drag the border of the window around.
227 | */
228 |
229 | static void mouse_windrag(WINDOW* wp)
230 | { uint x,y;
231 | LINE *lp;
232 | int doto;
233 |
234 | /* Continue dragging window until button goes up */
235 | while (msm_getstatus(&x,&y) & 1)
236 | {
237 | mouse_tocursor(&x,&y); /* collect real cursor coords */
238 | mouse_findpos(x,y,&wp,&lp,&doto);
239 | if (wp && wp == curwp && lp ||
240 | wp != curwp && wp && wp.w_toprow < curwp.w_toprow)
241 | window_shrink(FALSE,1);
242 | else if (!wp ||
243 | wp != curwp && wp.w_toprow > curwp.w_toprow)
244 | window_enlarge(FALSE,1);
245 | update();
246 | }
247 | }
248 |
249 | /*****************************
250 | * Return !=0 if left button is down.
251 | */
252 |
253 | static int mouse_leftisdown()
254 | { uint x,y;
255 |
256 | return msm_getstatus(&x,&y) & 1;
257 | }
258 |
--------------------------------------------------------------------------------
/src/med/region.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 | /*
11 | * The routines in this file
12 | * deal with the region, that magic space
13 | * between "." and mark. Some functions are
14 | * commands. Some functions are just for
15 | * internal use.
16 | */
17 |
18 | module region;
19 |
20 | import std.string;
21 | import std.ascii;
22 |
23 | import ed;
24 | import line;
25 | import main;
26 | import window;
27 | import display;
28 | import buffer;
29 |
30 | /*
31 | * The starting position of a region, and the size of the region in
32 | * characters, is kept in a region structure. Used by the region commands.
33 | */
34 | struct REGION {
35 | LINE *r_linep; /* Origin LINE address */
36 | uint r_offset; /* Origin LINE offset (not in col mode) */
37 | uint r_size; /* Length in characters (approx in col mode) */
38 | uint r_nlines; /* Number of lines */
39 | uint r_leftcol; /* Left column for column cut */
40 | uint r_rightcol; /* And right column */
41 | }
42 |
43 |
44 | /*********************************
45 | * Toggle column cut/paste mode.
46 | */
47 |
48 | int region_togglemode(bool f, int n)
49 | {
50 | column_mode ^= 1; /* toggle screen mode */
51 | line_change(WFHARD);
52 | mlwrite(column_mode ? "[Column mode on]" : "[Column mode off]");
53 | return TRUE;
54 | }
55 |
56 | /*
57 | * Kill the region. Ask "getregion"
58 | * to figure out the bounds of the region.
59 | * Move "." to the start, and kill the characters.
60 | */
61 | int region_kill(bool f, int n)
62 | {
63 | int s;
64 | REGION region;
65 |
66 | if (curbp.b_flag & BFRDONLY)
67 | return FALSE;
68 | if ((s=getregion(®ion)) != TRUE)
69 | goto err;
70 | if (region.r_size == 0)
71 | goto err; /* error if 0 length */
72 | if ((lastflag&CFKILL) == 0) /* This is a kill type */
73 | kill_freebuffer(); /* command, so do magic */
74 | thisflag |= CFKILL; /* kill buffer stuff. */
75 | curwp.w_dotp = region.r_linep;
76 | curwp.w_doto = region.r_offset;
77 | curwp.w_markp = null;
78 | if (column_mode)
79 | {
80 | if (!kill_setsize(region.r_size))
81 | return FALSE;
82 | while (region.r_nlines--)
83 | { int lright;
84 | LINE* linep = curwp.w_dotp;
85 |
86 | curwp.w_doto = coltodoto(linep,region.r_leftcol);
87 | lright = coltodoto(linep,region.r_rightcol);
88 | if (!line_delete(lright - curwp.w_doto, TRUE))
89 | goto err;
90 | if (!kill_appendchar('\n'))
91 | goto err;
92 | curwp.w_dotp = lforw(linep);
93 | }
94 | curwp.w_dotp = region.r_linep;
95 | curwp.w_doto = coltodoto(region.r_linep,region.r_leftcol);
96 | line_change(WFHARD);
97 | }
98 | else
99 | s = line_delete(region.r_size, TRUE);
100 | kill_toClipboard();
101 | return s;
102 | err:
103 | return FALSE;
104 | }
105 |
106 | /*
107 | * Copy all of the characters in the
108 | * region to the kill buffer. Don't move dot
109 | * at all. This is a bit like a kill region followed
110 | * by a yank. Bound to "M-W".
111 | */
112 | int region_copy(bool f, int n)
113 | {
114 | LINE* linep;
115 | int loffs;
116 | int s;
117 | REGION region;
118 |
119 | if ((s=getregion(®ion)) != TRUE)
120 | return (s);
121 | if ((lastflag&CFKILL) == 0) /* Kill type command. */
122 | kill_freebuffer();
123 |
124 | /* Turn off marked region */
125 | curwp.w_markp = null;
126 | curwp.w_flag |= WFHARD;
127 |
128 | thisflag |= CFKILL;
129 | linep = region.r_linep; /* Current line. */
130 | loffs = region.r_offset; /* Current offset. */
131 | if (!kill_setsize(region.r_size))
132 | return FALSE;
133 | if (column_mode)
134 | {
135 | while (region.r_nlines--)
136 | { int lright;
137 | int lleft;
138 |
139 | lleft = coltodoto(linep,region.r_leftcol);
140 | lright = coltodoto(linep,region.r_rightcol);
141 | if (!kill_appendstring(linep.l_text[lleft .. lright]))
142 | goto err;
143 | if (!kill_appendchar('\n'))
144 | goto err;
145 | linep = lforw(linep);
146 | }
147 | }
148 | else
149 | while (region.r_size) {
150 | if (loffs == llength(linep)) { /* End of line. */
151 | if (kill_appendchar('\n') != TRUE)
152 | return FALSE;
153 | linep = lforw(linep);
154 | loffs = 0;
155 | region.r_size--;
156 | } else { /* Middle of line. */
157 | int i;
158 |
159 | i = llength(linep) - loffs;
160 | if (i > region.r_size)
161 | i = region.r_size;
162 | if (kill_appendstring(linep.l_text[loffs .. loffs + i]) != TRUE)
163 | return FALSE;
164 | loffs += i;
165 | region.r_size -= i;
166 | }
167 | }
168 | kill_toClipboard();
169 | return (TRUE);
170 |
171 | err: return FALSE;
172 | }
173 |
174 | /*
175 | * Upper/lower case region. Zap all of the upper
176 | * case characters in the region to lower case. Use
177 | * the region code to set the limits. Scan the buffer,
178 | * doing the changes. Call "line_change" to ensure that
179 | * redisplay is done in all buffers.
180 | */
181 | int region_lower(bool f, int n)
182 | {
183 | return region_case(TRUE);
184 | }
185 |
186 | int region_upper(bool f, int n)
187 | {
188 | return region_case(FALSE);
189 | }
190 |
191 | private int region_case(bool flag)
192 | {
193 | LINE* linep;
194 | int loffs;
195 | int c;
196 | int s;
197 | REGION region;
198 |
199 | if ((s=getregion(®ion)) != TRUE)
200 | return (s);
201 | line_change(WFHARD);
202 | /*curwp.w_markp = null;*/
203 | linep = region.r_linep;
204 | if (column_mode)
205 | {
206 | while (region.r_nlines--)
207 | { int lright;
208 |
209 | loffs = coltodoto(linep,region.r_leftcol);
210 | lright = coltodoto(linep,region.r_rightcol);
211 | for (; loffs < lright; loffs++)
212 | { c = lgetc(linep, loffs);
213 | if (flag ? isUpper(c) : isLower(c))
214 | lputc(linep, loffs, cast(char)(c ^ 0x20));
215 | }
216 | linep = lforw(linep);
217 | }
218 | }
219 | else
220 | {
221 | loffs = region.r_offset;
222 | while (region.r_size--) {
223 | if (loffs == llength(linep)) {
224 | linep = lforw(linep);
225 | loffs = 0;
226 | } else {
227 | c = lgetc(linep, loffs);
228 | if (flag ? isUpper(c) : isLower(c))
229 | lputc(linep, loffs, cast(char)(c ^ 0x20));
230 | ++loffs;
231 | }
232 | }
233 | }
234 | return (TRUE);
235 | }
236 |
237 | /*
238 | * This routine figures out the
239 | * bounds of the region in the current window, and
240 | * fills in the fields of the "REGION" structure pointed
241 | * to by "rp". Because the dot and mark are usually very
242 | * close together, we scan outward from dot looking for
243 | * mark. This should save time. Return a standard code.
244 | * Callers of this routine should be prepared to get
245 | * an "ABORT" status; we might make this have the
246 | * conform thing later.
247 | */
248 | int getregion(REGION* rp)
249 | {
250 | LINE *flp;
251 | LINE *blp;
252 | int nlines; /* number of lines in region */
253 | int fsize;
254 | int bsize;
255 | int size;
256 |
257 | if (!window_marking(curwp)) {
258 | mlwrite("No mark set in this window");
259 | return (FALSE);
260 | }
261 |
262 | /* Figure out left and right columns, this is valid only if */
263 | /* column cut mode is on. */
264 | if (markcol < curgoal)
265 | { rp.r_leftcol = markcol;
266 | rp.r_rightcol = curgoal;
267 | }
268 | else
269 | { rp.r_leftcol = curgoal;
270 | rp.r_rightcol = markcol;
271 | }
272 |
273 | rp.r_nlines = 1; /* always at least 1 line */
274 |
275 | /* If region lies within one line */
276 | if (curwp.w_dotp == curwp.w_markp)
277 | { rp.r_linep = curwp.w_dotp;
278 | if (column_mode)
279 | {
280 | rp.r_size = rp.r_rightcol - rp.r_leftcol;
281 | }
282 | else
283 | {
284 | if (curwp.w_doto < curwp.w_marko)
285 | { rp.r_offset = curwp.w_doto;
286 | rp.r_size = curwp.w_marko-curwp.w_doto;
287 | }
288 | else
289 | { rp.r_offset = curwp.w_marko;
290 | rp.r_size = curwp.w_doto-curwp.w_marko;
291 | }
292 | }
293 | return (TRUE);
294 | }
295 |
296 | blp = curwp.w_dotp;
297 | bsize = curwp.w_doto;
298 | flp = curwp.w_dotp;
299 | fsize = llength(flp)-curwp.w_doto+1;
300 | while (flp!=curbp.b_linep || lback(blp)!=curbp.b_linep)
301 | {
302 | rp.r_nlines++;
303 | if (flp != curbp.b_linep) {
304 | flp = lforw(flp);
305 | if (flp == curwp.w_markp) {
306 | rp.r_linep = curwp.w_dotp;
307 | rp.r_offset = curwp.w_doto;
308 | size = fsize+curwp.w_marko;
309 | /* Don't count last line if it's at start */
310 | if (curwp.w_marko == 0)
311 | rp.r_nlines--;
312 | goto done;
313 | }
314 | fsize += llength(flp)+1;
315 | }
316 | if (lback(blp) != curbp.b_linep) {
317 | blp = lback(blp);
318 | bsize += llength(blp)+1;
319 | if (blp == curwp.w_markp) {
320 | rp.r_linep = blp;
321 | rp.r_offset = curwp.w_marko;
322 | size = bsize - curwp.w_marko;
323 | /* Don't count last line if it's at start */
324 | if (curwp.w_doto == 0)
325 | rp.r_nlines--;
326 | goto done;
327 | }
328 | }
329 | }
330 | mlwrite("Bug: lost mark");
331 | return (FALSE);
332 |
333 | done:
334 | if (column_mode)
335 | size = (rp.r_rightcol - rp.r_leftcol + 1) * rp.r_nlines;
336 | rp.r_size = size;
337 | return TRUE;
338 | }
339 |
--------------------------------------------------------------------------------
/src/med/spawn.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 |
11 | /*
12 | * The routines in this file are called to create a subjob running a command
13 | * interpreter.
14 | */
15 |
16 | module spawn;
17 |
18 | import core.stdc.stdlib;
19 | import core.stdc.time;
20 |
21 | import std.conv;
22 | import std.stdio;
23 | import std.file;
24 | import std.process;
25 | import std.string;
26 | import std.utf;
27 |
28 | version(Posix)
29 | {
30 | import core.sys.posix.unistd;
31 | }
32 |
33 | import ed;
34 | import buffer;
35 | import window;
36 | import display;
37 | import main;
38 | import file;
39 | import terminal;
40 |
41 |
42 |
43 | /*
44 | * Create a subjob with a copy of the command intrepreter in it. When the
45 | * command interpreter exits, mark the screen as garbage so that you do a full
46 | * repaint. Bound to "C-C". The message at the start in VMS puts out a newline.
47 | * Under some (unknown) condition, you don't get one free when DCL starts up.
48 | */
49 | int spawncli(bool f, int n)
50 | {
51 | movecursor(term.t_nrow-1, 0); /* Seek to last line. */
52 | version (Windows)
53 | {
54 | term.t_flush();
55 | auto comspec = core.stdc.stdlib.getenv("COMSPEC");
56 | string[] args;
57 | args ~= to!string(comspec);
58 | args ~= "COMMAND.COM";
59 | spawnProcess(args);
60 | }
61 | version (Posix)
62 | {
63 | term.t_flush();
64 | term.t_close(); /* stty to old settings */
65 | auto cp = core.stdc.stdlib.getenv("SHELL");
66 | if (cp && *cp != '\0')
67 | core.stdc.stdlib.system(cp);
68 | else
69 | core.stdc.stdlib.system("exec /bin/sh");
70 | sleep(2);
71 | term.t_open();
72 | }
73 | sgarbf = TRUE;
74 | return(TRUE);
75 | }
76 |
77 | /*
78 | * Run a one-liner in a subjob. When the command returns, wait for a single
79 | * character to be typed, then mark the screen as garbage so a full repaint is
80 | * done. Bound to "C-X !".
81 | */
82 | int spawn(bool f, int n)
83 | {
84 | int s;
85 | string line;
86 | version (Windows)
87 | {
88 | if ((s=mlreply("MS-DOS command: ", null, line)) != TRUE)
89 | return (s);
90 | core.stdc.stdlib.system(toUTF8(line).toStringz());
91 | while (term.t_getchar() != '\r') /* Pause. */
92 | {
93 | }
94 | sgarbf = TRUE;
95 | return (TRUE);
96 | }
97 | version (Posix)
98 | {
99 | if ((s=mlreply("! ", null, line)) != TRUE)
100 | return (s);
101 | term.t_putchar('\n'); /* Already have '\r' */
102 | term.t_flush();
103 | term.t_close(); /* stty to old modes */
104 | core.stdc.stdlib.system(toUTF8(line).toStringz());
105 | sleep(2);
106 | term.t_open();
107 | printf("[End]"); /* Pause. */
108 | term.t_flush();
109 | while ((s = term.t_getchar()) != '\r' && s != ' ')
110 | {
111 | }
112 | sgarbf = TRUE;
113 | return (TRUE);
114 | }
115 | }
116 |
117 | /*
118 | * Pipe a one line command into a window
119 | * Bound to ^X @
120 | */
121 | int spawn_pipe(bool f, int n)
122 | {
123 | int s; /* return status from CLI */
124 | WINDOW *wp; /* pointer to new window */
125 | BUFFER *bp; /* pointer to buffer to zot */
126 | static string bname = "[DOS]";
127 |
128 | static string filnam = "DOS.TMP";
129 | string line; /* command line sent to shell */
130 | string sline;
131 |
132 | /* get the command to pipe in */
133 | if ((s = mlreply("DOS:", null, line)) != TRUE)
134 | return s;
135 |
136 | /* get rid of the command output buffer if it exists */
137 | if ((bp=buffer_find(bname, FALSE, BFTEMP)) != null) /* if buffer exists */
138 | {
139 | /* If buffer is displayed, try to move it off screen */
140 | /* (can't remove an on-screen buffer) */
141 | if (bp.b_nwnd) /* if buffer is displayed */
142 | { if (bp == curbp) /* if it's the current window */
143 | window_next(FALSE,1); /* make another window current */
144 | window_only(FALSE, 1);
145 |
146 | if (buffer_remove(bp) != TRUE)
147 | goto fail;
148 | }
149 | }
150 |
151 | /* split the current window to make room for the command output */
152 | if (window_split(FALSE, 1) == FALSE)
153 | goto fail;
154 |
155 | sline = toUTF8(line) ~ ">" ~ filnam;
156 |
157 | version (Windows)
158 | {
159 | movecursor(term.t_nrow - 2, 0);
160 | core.stdc.stdlib.system(sline.toStringz());
161 | sgarbf = TRUE;
162 | if (std.file.exists(filnam) && std.file.isFile(filnam))
163 | return FALSE;
164 | }
165 | version (Posix)
166 | {
167 | term.t_putchar('\n'); /* Already have '\r' */
168 | term.t_flush();
169 | term.t_close(); /* stty to old modes */
170 | core.stdc.stdlib.system(sline.toStringz());
171 | term.t_open();
172 | term.t_flush();
173 | sgarbf = TRUE;
174 | }
175 |
176 | /* and read the stuff in */
177 | if (file_readin(filnam) == FALSE)
178 | return(FALSE);
179 |
180 | /* and get rid of the temporary file */
181 | remove(filnam);
182 | return(TRUE);
183 |
184 | fail:
185 | return FALSE;
186 | }
187 |
188 | /*
189 | * filter a buffer through an external DOS program
190 | * Bound to ^X #
191 | */
192 | int spawn_filter(bool f, int n)
193 | {
194 | int s; /* return status from CLI */
195 | BUFFER *bp; /* pointer to buffer to zot */
196 | string line; /* command line to send to shell */
197 | string tmpnam; /* place to store real file name */
198 | string bname1 = "fltinp";
199 |
200 | string filnam1 = "fltinp";
201 | string filnam2 = "fltout";
202 |
203 | if (curbp.b_flag & BFRDONLY) /* if buffer is read-only */
204 | return FALSE; /* fail */
205 |
206 | /* get the filter name and its args */
207 | if ((s=mlreply("Filter:", null, line)) != TRUE)
208 | return(s);
209 |
210 | /* setup the proper file names */
211 | bp = curbp;
212 | tmpnam = bp.b_fname; /* save the original name */
213 | bp.b_fname = bname1; /* set it to our new one */
214 |
215 | /* write it out, checking for errors */
216 | if (writeout(filnam1) != TRUE) {
217 | mlwrite("[Cannot write filter file]");
218 | bp.b_fname = tmpnam;
219 | return(FALSE);
220 | }
221 |
222 | line ~= " fltout";
223 | version (Windows)
224 | {
225 | movecursor(term.t_nrow - 2, 0);
226 | core.stdc.stdlib.system(toUTF8(line).toStringz());
227 | }
228 | version (Posix)
229 | {
230 | term.t_putchar('\n'); /* Already have '\r' */
231 | term.t_flush();
232 | term.t_close(); /* stty to old modes */
233 | core.stdc.stdlib.system(toUTF8(line).toStringz());
234 | term.t_open();
235 | term.t_flush();
236 | }
237 |
238 | sgarbf = TRUE;
239 | s = TRUE;
240 |
241 | /* on failure, escape gracefully */
242 | if (s != TRUE || ((s = readin(filnam2)) == FALSE)) {
243 | mlwrite("[Execution failed]");
244 | bp.b_fname = tmpnam;
245 | goto ret;
246 | }
247 |
248 | /* reset file name */
249 | bp.b_fname = tmpnam; /* restore name */
250 | bp.b_flag |= BFCHG; /* flag it as changed */
251 | s = TRUE;
252 |
253 | ret:
254 | /* and get rid of the temporary file */
255 | remove(toUTF8(filnam1));
256 | remove(toUTF8(filnam2));
257 | return s;
258 | }
259 |
260 |
261 |
--------------------------------------------------------------------------------
/src/med/syntaxc.d:
--------------------------------------------------------------------------------
1 |
2 | /* This version of microEmacs is based on the public domain C
3 | * version written by Dave G. Conroy.
4 | * The D programming language version is written by Walter Bright.
5 | * http://www.digitalmars.com/d/
6 | * This program is in the public domain.
7 | */
8 |
9 | /* This is the C syntax highligher.
10 | */
11 |
12 | module syntaxc;
13 |
14 | import core.stdc.stdio;
15 | import core.stdc.ctype;
16 |
17 | import std.utf;
18 |
19 | import ed;
20 | import buffer;
21 | import window;
22 | import main;
23 | import display;
24 | import random;
25 |
26 | /********************************
27 | * Returns:
28 | * starting syntax state of next line
29 | */
30 | SyntaxState syntaxHighlightC(SyntaxState syntaxState, const(char)[] text, attr_t[] attr)
31 | {
32 | size_t i = 0;
33 |
34 | switch (syntaxState.syntax)
35 | {
36 | case Syntax.string:
37 | case Syntax.singleString:
38 | {
39 | const quote = (syntaxState.syntax == Syntax.string) ? '"' :
40 | '\'';
41 | const istart = i;
42 | bool escape;
43 | while (i < text.length)
44 | {
45 | if (text[i] == quote && !escape)
46 | {
47 | ++i;
48 | attr[istart .. i] = config.string;
49 | goto Loop;
50 | }
51 | else if (text[i] == '\\')
52 | escape ^= true;
53 | else
54 | escape = false;
55 | ++i;
56 | }
57 | attr[istart .. i] = config.string;
58 | return SyntaxState(syntaxState.syntax);
59 | }
60 |
61 | case Syntax.comment:
62 | {
63 | // it's /* */ comment
64 | const istart = i;
65 | while (i < text.length)
66 | {
67 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
68 | {
69 | i += 2;
70 | attr[istart .. i] = config.comment;
71 | goto Loop;
72 | }
73 | ++i;
74 | }
75 | attr[istart .. i] = config.comment;
76 | return SyntaxState(Syntax.comment);
77 | }
78 |
79 | default:
80 | break;
81 | }
82 |
83 | Loop:
84 | while (i < text.length)
85 | {
86 | const c = text[i];
87 | switch (c)
88 | {
89 | case 'a': .. case 'z':
90 | case 'A': .. case 'Z':
91 | case '_':
92 | Idstart:
93 | {
94 | const istart = i;
95 | ++i;
96 | while (i < text.length)
97 | {
98 | const ci = text[i];
99 | if (isalnum(ci) || ci == '_' || ci & 0x80)
100 | {
101 | ++i;
102 | continue;
103 | }
104 | break;
105 | }
106 | const id = text[istart .. i];
107 | attr[istart .. i] = isCKeyword(id) ? config.keyword : config.normattr;
108 | continue;
109 | }
110 |
111 | case '/':
112 | {
113 | const istart = i;
114 | ++i;
115 | if (i < text.length)
116 | {
117 | if (text[i] == '/')
118 | {
119 | attr[istart .. text.length] = config.comment;
120 | return SyntaxState(Syntax.normal);
121 | }
122 |
123 | if (text[i] == '*')
124 | {
125 | ++i;
126 | while (i < text.length)
127 | {
128 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
129 | {
130 | i += 2;
131 | attr[istart .. i] = config.comment;
132 | continue Loop;
133 | }
134 | ++i;
135 | }
136 | attr[istart .. i] = config.comment;
137 | return SyntaxState(Syntax.comment);
138 | }
139 | }
140 | continue;
141 | }
142 |
143 | case '"':
144 | case '\'':
145 | {
146 | const istart = i;
147 | bool escape;
148 | ++i;
149 | while (i < text.length)
150 | {
151 | if (text[i] == c && !escape)
152 | {
153 | ++i;
154 | attr[istart .. i] = config.string;
155 | continue Loop;
156 | }
157 | else if (text[i] == '\\')
158 | escape ^= true;
159 | else
160 | escape = false;
161 | ++i;
162 | }
163 | attr[istart .. i] = config.string;
164 | return SyntaxState(c == '"' ? Syntax.string :
165 | Syntax.singleString);
166 | }
167 |
168 | default:
169 | if (text[i] & 0x80)
170 | goto Idstart;
171 | attr[i] = config.normattr;
172 | ++i;
173 | continue;
174 | }
175 | /*
176 | switch (syntaxState.syntax)
177 | {
178 | case Syntax.normal:
179 | break;
180 |
181 | case Syntax.string:
182 | case Syntax.singleString:
183 | break;
184 |
185 | case Syntax.comment:
186 | break;
187 |
188 | default:
189 | assert(0);
190 | }
191 | */
192 | }
193 | return SyntaxState(Syntax.normal);
194 | }
195 |
196 | private bool isCKeyword(const(char)[] s)
197 | {
198 | switch (s)
199 | {
200 | case "break":
201 | case "inline":
202 | case "void":
203 | case "case":
204 | case "if":
205 | case "int":
206 | case "volatile":
207 | case "char":
208 | case "long":
209 | case "while ":
210 | case "const":
211 | case "register":
212 | case "continue":
213 | case "restrict":
214 | case "default":
215 | case "return":
216 | case "do":
217 | case "short":
218 | case "double":
219 | case "signed":
220 | case "else":
221 | case "sizeof":
222 | case "enum":
223 | case "static":
224 | case "extern":
225 | case "struct":
226 | case "float":
227 | case "switch":
228 | case "for":
229 | case "typedef":
230 | case "goto":
231 | case "union ":
232 | case "_Alignas ":
233 | case "_Alignof ":
234 | case "_Atomic ":
235 | case "_Bool ":
236 | case "_Complex ":
237 | case "_Generic ":
238 | case "_Imaginary ":
239 | case "_Noreturn ":
240 | case "_Static_assert ":
241 | case "_Thread_local ":
242 | case "__FILE__":
243 | case "__LINE__":
244 | return true;
245 |
246 | default:
247 | return false;
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/src/med/syntaxcpp.d:
--------------------------------------------------------------------------------
1 |
2 | /* This version of microEmacs is based on the public domain C
3 | * version written by Dave G. Conroy.
4 | * The D programming language version is written by Walter Bright.
5 | * http://www.digitalmars.com/d/
6 | * This program is in the public domain.
7 | */
8 |
9 | /* This is the C++ syntax highligher.
10 | */
11 |
12 | module syntaxcpp;
13 |
14 | import core.stdc.stdio;
15 | import core.stdc.ctype;
16 |
17 | import std.utf;
18 |
19 | import ed;
20 | import buffer;
21 | import window;
22 | import main;
23 | import display;
24 | import random;
25 |
26 | /********************************
27 | * Returns:
28 | * starting syntax state of next line
29 | */
30 | SyntaxState syntaxHighlightCPP(SyntaxState syntaxState, const(char)[] text, attr_t[] attr)
31 | {
32 | size_t i = 0;
33 |
34 | switch (syntaxState.syntax)
35 | {
36 | case Syntax.string:
37 | case Syntax.singleString:
38 | {
39 | const quote = (syntaxState.syntax == Syntax.string) ? '"' :
40 | '\'';
41 | const istart = i;
42 | bool escape;
43 | while (i < text.length)
44 | {
45 | if (text[i] == quote && !escape)
46 | {
47 | ++i;
48 | attr[istart .. i] = config.string;
49 | goto Loop;
50 | }
51 | else if (text[i] == '\\')
52 | escape ^= true;
53 | else
54 | escape = false;
55 | ++i;
56 | }
57 | attr[istart .. i] = config.string;
58 | return SyntaxState(syntaxState.syntax);
59 | }
60 |
61 | case Syntax.comment:
62 | {
63 | // it's /* */ comment
64 | const istart = i;
65 | while (i < text.length)
66 | {
67 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
68 | {
69 | i += 2;
70 | attr[istart .. i] = config.comment;
71 | goto Loop;
72 | }
73 | ++i;
74 | }
75 | attr[istart .. i] = config.comment;
76 | return SyntaxState(Syntax.comment);
77 | }
78 |
79 | default:
80 | break;
81 | }
82 |
83 | Loop:
84 | while (i < text.length)
85 | {
86 | const c = text[i];
87 | switch (c)
88 | {
89 | case 'a': .. case 'z':
90 | case 'A': .. case 'Z':
91 | case '_':
92 | Idstart:
93 | {
94 | const istart = i;
95 | ++i;
96 | while (i < text.length)
97 | {
98 | const ci = text[i];
99 | if (isalnum(ci) || ci == '_' || ci & 0x80)
100 | {
101 | ++i;
102 | continue;
103 | }
104 | break;
105 | }
106 | const id = text[istart .. i];
107 | attr[istart .. i] = isCPPKeyword(id) ? config.keyword : config.normattr;
108 | continue;
109 | }
110 |
111 | case '/':
112 | {
113 | const istart = i;
114 | ++i;
115 | if (i < text.length)
116 | {
117 | if (text[i] == '/')
118 | {
119 | attr[istart .. text.length] = config.comment;
120 | return SyntaxState(Syntax.normal);
121 | }
122 |
123 | if (text[i] == '*')
124 | {
125 | ++i;
126 | while (i < text.length)
127 | {
128 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
129 | {
130 | i += 2;
131 | attr[istart .. i] = config.comment;
132 | continue Loop;
133 | }
134 | ++i;
135 | }
136 | attr[istart .. i] = config.comment;
137 | return SyntaxState(Syntax.comment);
138 | }
139 | }
140 | continue;
141 | }
142 |
143 | case '"':
144 | case '\'':
145 | {
146 | const istart = i;
147 | bool escape;
148 | ++i;
149 | while (i < text.length)
150 | {
151 | if (text[i] == c && !escape)
152 | {
153 | ++i;
154 | attr[istart .. i] = config.string;
155 | continue Loop;
156 | }
157 | else if (text[i] == '\\')
158 | escape ^= true;
159 | else
160 | escape = false;
161 | ++i;
162 | }
163 | attr[istart .. i] = config.string;
164 | return SyntaxState(c == '"' ? Syntax.string :
165 | Syntax.singleString);
166 | }
167 |
168 | default:
169 | if (text[i] & 0x80)
170 | goto Idstart;
171 | attr[i] = config.normattr;
172 | ++i;
173 | continue;
174 | }
175 | /*
176 | switch (syntaxState.syntax)
177 | {
178 | case Syntax.normal:
179 | break;
180 |
181 | case Syntax.string:
182 | case Syntax.singleString:
183 | break;
184 |
185 | case Syntax.comment:
186 | break;
187 |
188 | default:
189 | assert(0);
190 | }
191 | */
192 | }
193 | return SyntaxState(Syntax.normal);
194 | }
195 |
196 | private bool isCPPKeyword(const(char)[] s)
197 | {
198 | switch (s)
199 | {
200 | case "alignas":
201 | case "const_cast":
202 | case "for":
203 | case "public":
204 | case "thread_local ":
205 | case "alignof":
206 | case "continue":
207 | case "friend":
208 | case "register":
209 | case "throw":
210 | case "asm":
211 | case "decltype":
212 | case "goto":
213 | case "reinterpret_cast":
214 | case "true ":
215 | case "auto":
216 | case "default":
217 | case "if":
218 | case "requires":
219 | case "try ":
220 | case "bool":
221 | case "delete":
222 | case "inline":
223 | case "return":
224 | case "typedef ":
225 | case "break":
226 | case "do":
227 | case "int":
228 | case "short":
229 | case "typeid ":
230 | case "case":
231 | case "double":
232 | case "long":
233 | case "signed":
234 | case "typename ":
235 | case "catch":
236 | case "dynamic_cast":
237 | case "mutable":
238 | case "sizeof":
239 | case "union ":
240 | case "char":
241 | case "else":
242 | case "namespace":
243 | case "static":
244 | case "unsigned ":
245 | case "char16_t":
246 | case "enum":
247 | case "new":
248 | case "static_assert":
249 | case "using ":
250 | case "char32_t":
251 | case "explicit":
252 | case "noexcept":
253 | case "static_cast":
254 | case "virtual ":
255 | case "class":
256 | case "export":
257 | case "nullptr":
258 | case "struct":
259 | case "void ":
260 | case "concept":
261 | case "extern":
262 | case "operator":
263 | case "switch":
264 | case "volatile ":
265 | case "const":
266 | case "false":
267 | case "private":
268 | case "template":
269 | case "wchar_t ":
270 | case "constexpr":
271 | case "float":
272 | case "protected":
273 | case "this":
274 | case "while":
275 |
276 | case "and":
277 | case "and_eq":
278 | case "bitand":
279 | case "bitor":
280 | case "compl":
281 | case "not ":
282 | case "not_eq":
283 | case "or":
284 | case "or_eq":
285 | case "xor":
286 | case "xor_eq ":
287 |
288 | case "__FILE__":
289 | case "__LINE__":
290 | return true;
291 |
292 | default:
293 | return false;
294 | }
295 | }
296 |
--------------------------------------------------------------------------------
/src/med/syntaxd.d:
--------------------------------------------------------------------------------
1 |
2 | /* This version of microEmacs is based on the public domain C
3 | * version written by Dave G. Conroy.
4 | * The D programming language version is written by Walter Bright.
5 | * http://www.digitalmars.com/d/
6 | * This program is in the public domain.
7 | */
8 |
9 | /* This is the D syntax highligher.
10 | */
11 |
12 | module syntaxd;
13 |
14 | import core.stdc.stdio;
15 | import core.stdc.ctype;
16 |
17 | import std.utf;
18 |
19 | import ed;
20 | import buffer;
21 | import window;
22 | import main;
23 | import display;
24 | import random;
25 |
26 | /********************************
27 | * Returns:
28 | * starting syntax state of next line
29 | */
30 | SyntaxState syntaxHighlightD(SyntaxState syntaxState, const(char)[] text, attr_t[] attr)
31 | {
32 | size_t i = 0;
33 |
34 | switch (syntaxState.syntax)
35 | {
36 | case Syntax.string:
37 | case Syntax.singleString:
38 | case Syntax.backtickString:
39 | {
40 | const quote = (syntaxState.syntax == Syntax.string) ? '"' :
41 | (syntaxState.syntax == Syntax.singleString) ? '\'' :
42 | '`';
43 | const istart = i;
44 | bool escape;
45 | while (i < text.length)
46 | {
47 | if (text[i] == quote && !escape)
48 | {
49 | ++i;
50 | attr[istart .. i] = config.string;
51 | goto Loop;
52 | }
53 | else if (text[i] == '\\' && quote != '`')
54 | escape ^= true;
55 | else
56 | escape = false;
57 | ++i;
58 | }
59 | attr[istart .. i] = config.string;
60 | return SyntaxState(syntaxState.syntax);
61 | }
62 |
63 | case Syntax.comment:
64 | {
65 | if (syntaxState.nest) // it's /+ +/ nested comment
66 | {
67 | const istart = i;
68 | uint nest = syntaxState.nest;
69 | while (i < text.length)
70 | {
71 | if (text[i] == '+' && i + 1 < text.length && text[i + 1] == '/')
72 | {
73 | i += 2;
74 | --nest;
75 | if (nest == 0)
76 | {
77 | attr[istart .. i] = config.comment;
78 | goto Loop;
79 | }
80 | continue;
81 | }
82 | if (text[i] == '/' && i + 1 < text.length && text[i + 1] == '+')
83 | {
84 | i += 2;
85 | ++nest;
86 | continue;
87 | }
88 | ++i;
89 | }
90 | attr[istart .. i] = config.comment;
91 | return SyntaxState(Syntax.comment, nest);
92 | }
93 | else // it's /* */ comment
94 | {
95 | const istart = i;
96 | while (i < text.length)
97 | {
98 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
99 | {
100 | i += 2;
101 | attr[istart .. i] = config.comment;
102 | goto Loop;
103 | }
104 | ++i;
105 | }
106 | attr[istart .. i] = config.comment;
107 | return SyntaxState(Syntax.comment);
108 | }
109 | }
110 |
111 | default:
112 | break;
113 | }
114 |
115 | Loop:
116 | while (i < text.length)
117 | {
118 | const c = text[i];
119 | switch (c)
120 | {
121 | case 'a': .. case 'z':
122 | case 'A': .. case 'Z':
123 | case '_':
124 | Idstart:
125 | {
126 | const istart = i;
127 | ++i;
128 | while (i < text.length)
129 | {
130 | const ci = text[i];
131 | if (isalnum(ci) || ci == '_' || ci & 0x80)
132 | {
133 | ++i;
134 | continue;
135 | }
136 | break;
137 | }
138 | const id = text[istart .. i];
139 | attr[istart .. i] = isDKeyword(id) ? config.keyword : config.normattr;
140 | continue;
141 | }
142 |
143 | case '/':
144 | {
145 | const istart = i;
146 | ++i;
147 | if (i < text.length)
148 | {
149 | if (text[i] == '/')
150 | {
151 | attr[istart .. text.length] = config.comment;
152 | return SyntaxState(Syntax.normal);
153 | }
154 |
155 | if (text[i] == '*')
156 | {
157 | ++i;
158 | while (i < text.length)
159 | {
160 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
161 | {
162 | i += 2;
163 | attr[istart .. i] = config.comment;
164 | continue Loop;
165 | }
166 | ++i;
167 | }
168 | attr[istart .. i] = config.comment;
169 | return SyntaxState(Syntax.comment);
170 | }
171 |
172 | if (text[i] == '+')
173 | {
174 | uint nest = 1;
175 | ++i;
176 | while (i < text.length)
177 | {
178 | if (text[i] == '+' && i + 1 < text.length && text[i + 1] == '/')
179 | {
180 | i += 2;
181 | --nest;
182 | if (nest == 0)
183 | {
184 | attr[istart .. i] = config.comment;
185 | continue Loop;
186 | }
187 | continue;
188 | }
189 | if (text[i] == '/' && i + 1 < text.length && text[i + 1] == '+')
190 | {
191 | i += 2;
192 | ++nest;
193 | continue;
194 | }
195 | ++i;
196 | }
197 | attr[istart .. i] = config.comment;
198 | return SyntaxState(Syntax.comment, nest);
199 | }
200 | }
201 | continue;
202 | }
203 |
204 | case '"':
205 | case '\'':
206 | case '`':
207 | {
208 | const istart = i;
209 | bool escape;
210 | ++i;
211 | while (i < text.length)
212 | {
213 | if (text[i] == c && !escape)
214 | {
215 | ++i;
216 | attr[istart .. i] = config.string;
217 | continue Loop;
218 | }
219 | else if (text[i] == '\\' && c != '`')
220 | escape ^= true;
221 | else
222 | escape = false;
223 | ++i;
224 | }
225 | attr[istart .. i] = config.string;
226 | return SyntaxState(c == '"' ? Syntax.string :
227 | c == '\'' ? Syntax.singleString :
228 | Syntax.backtickString);
229 | }
230 |
231 | default:
232 | if (text[i] & 0x80)
233 | goto Idstart;
234 | attr[i] = config.normattr;
235 | ++i;
236 | continue;
237 | }
238 | /*
239 | switch (syntaxState.syntax)
240 | {
241 | case Syntax.normal:
242 | break;
243 |
244 | case Syntax.string:
245 | case Syntax.singleString:
246 | break;
247 |
248 | case Syntax.comment:
249 | break;
250 |
251 | default:
252 | assert(0);
253 | }
254 | */
255 | }
256 | return SyntaxState(Syntax.normal);
257 | }
258 |
259 | private bool isDKeyword(const(char)[] s)
260 | {
261 | switch (s)
262 | {
263 | case "this":
264 | case "super":
265 | case "assert":
266 | case "null":
267 | case "true":
268 | case "false":
269 | case "cast":
270 | case "new":
271 | case "delete":
272 | case "throw":
273 | case "module":
274 | case "pragma":
275 | case "typeof":
276 | case "typeid":
277 | case "template":
278 | case "void":
279 | case "byte":
280 | case "ubyte":
281 | case "short":
282 | case "ushort":
283 | case "int":
284 | case "uint":
285 | case "long":
286 | case "ulong":
287 | case "cent":
288 | case "ucent":
289 | case "float":
290 | case "double":
291 | case "real":
292 | case "bool":
293 | case "char":
294 | case "wchar":
295 | case "dchar":
296 | case "ifloat":
297 | case "idouble":
298 | case "ireal":
299 | case "cfloat":
300 | case "cdouble":
301 | case "creal":
302 | case "delegate":
303 | case "function":
304 | case "is":
305 | case "if":
306 | case "else":
307 | case "while":
308 | case "for":
309 | case "do":
310 | case "switch":
311 | case "case":
312 | case "default":
313 | case "break":
314 | case "continue":
315 | case "synchronized":
316 | case "return":
317 | case "goto":
318 | case "try":
319 | case "catch":
320 | case "finally":
321 | case "with":
322 | case "asm":
323 | case "foreach":
324 | case "foreach_reverse":
325 | case "scope":
326 | case "struct":
327 | case "class":
328 | case "interface":
329 | case "union":
330 | case "enum":
331 | case "import":
332 | case "mixin":
333 | case "static":
334 | case "final":
335 | case "const":
336 | case "alias":
337 | case "override":
338 | case "abstract":
339 | case "debug":
340 | case "deprecated":
341 | case "in":
342 | case "out":
343 | case "inout":
344 | case "lazy":
345 | case "auto":
346 | case "align":
347 | case "extern":
348 | case "private":
349 | case "package":
350 | case "protected":
351 | case "public":
352 | case "export":
353 | case "invariant":
354 | case "unittest":
355 | case "version":
356 | case "__argTypes":
357 | case "__parameters":
358 | case "ref":
359 | case "macro":
360 | case "pure":
361 | case "nothrow":
362 | case "__gshared":
363 | case "__traits":
364 | case "__vector":
365 | case "__overloadset":
366 | case "__FILE__":
367 | case "__FILE_FULL_PATH__":
368 | case "__LINE__":
369 | case "__MODULE__":
370 | case "__FUNCTION__":
371 | case "__PRETTY_FUNCTION__":
372 | case "shared":
373 | case "immutable":
374 | return true;
375 |
376 | default:
377 | return false;
378 | }
379 | }
380 |
--------------------------------------------------------------------------------
/src/med/terminal.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 |
11 | version (Windows)
12 | {
13 | public import console;
14 | public import mouse;
15 | }
16 |
17 | version (Posix)
18 | {
19 | public import termio;
20 | public import xterm;
21 | }
22 |
--------------------------------------------------------------------------------
/src/med/termio.d:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * The functions in this file negotiate with the operating system for
4 | * characters, and write characters in a barely buffered fashion on the display.
5 | */
6 |
7 | module termio;
8 |
9 | version (Posix)
10 | {
11 |
12 | import core.stdc.stdio;
13 | import core.sys.posix.termios;
14 | import core.sys.posix.sys.ioctl;
15 |
16 | import ed;
17 |
18 | extern (C) void cfmakeraw(in termios*);
19 |
20 |
21 | termios ostate; /* saved tty state */
22 | termios nstate; /* values for editor mode */
23 |
24 |
25 | /*
26 | * This function is called once to set up the terminal device streams.
27 | * On VMS, it translates SYS$INPUT until it finds the terminal, then assigns
28 | * a channel to it and sets it raw. On CPM it is a no-op.
29 | */
30 | void ttopen()
31 | {
32 | /* Adjust output channel */
33 | tcgetattr(1, &ostate); /* save old state */
34 | tcgetattr(1, &nstate); /* get base of new state */
35 | cfmakeraw(&nstate);
36 | tcsetattr(1, TCSADRAIN, &nstate); /* set mode */
37 | }
38 |
39 | /*
40 | * This function gets called just before we go back home to the command
41 | * interpreter. On VMS it puts the terminal back in a reasonable state.
42 | * Another no-operation on CPM.
43 | */
44 | void ttclose()
45 | {
46 | tcsetattr(1, TCSADRAIN, &ostate); // return to original mode
47 | }
48 |
49 | /*
50 | * Write a character to the display. On VMS, terminal output is buffered, and
51 | * we just put the characters in the big array, after checking for overflow.
52 | * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
53 | * MS-DOS (use the very very raw console output routine).
54 | */
55 | void ttputc(char c)
56 | {
57 | fputc(c, stdout);
58 | }
59 |
60 | /*
61 | * Flush terminal buffer. Does real work where the terminal output is buffered
62 | * up. A no-operation on systems where byte at a time terminal I/O is done.
63 | */
64 | void ttflush()
65 | {
66 | fflush(stdout);
67 | }
68 |
69 | /*
70 | * Read a character from the terminal, performing no editing and doing no echo
71 | * at all. More complex in VMS that almost anyplace else, which figures. Very
72 | * simple on CPM, because the system can do exactly what you want.
73 | */
74 | int ttgetc()
75 | {
76 | return fgetc(stdin);
77 | }
78 |
79 | /**************************
80 | * Return TRUE if there are unread chars ready in the input.
81 | */
82 |
83 | int ttkeysininput()
84 | {
85 | int n;
86 | ioctl(0, FIONREAD, &n);
87 | return n != 0;
88 | }
89 |
90 | /**************************
91 | * Return when there are unread chars ready in the input.
92 | */
93 |
94 | void ttwaitkeys()
95 | {
96 | import core.sys.posix.sys.select;
97 | fd_set readfds;
98 | FD_ZERO(&readfds);
99 | FD_SET(0, &readfds);
100 | select(1, &readfds, null, null, null);
101 | }
102 |
103 | /******************************
104 | */
105 |
106 | void ttyield()
107 | {
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/src/med/testkbd.d:
--------------------------------------------------------------------------------
1 |
2 | module testkbd;
3 |
4 | version (Posix)
5 | {
6 |
7 | import core.stdc.stdio;
8 | import core.sys.posix.termios;
9 | import core.sys.posix.sys.ioctl;
10 |
11 | import ed;
12 |
13 | extern (C) void cfmakeraw(in termios*);
14 |
15 |
16 | termios ostate; /* saved tty state */
17 | termios nstate; /* values for editor mode */
18 |
19 |
20 | /*
21 | * This function is called once to set up the terminal device streams.
22 | * On VMS, it translates SYS$INPUT until it finds the terminal, then assigns
23 | * a channel to it and sets it raw. On CPM it is a no-op.
24 | */
25 | void ttopen()
26 | {
27 | /* Adjust output channel */
28 | tcgetattr(1, &ostate); /* save old state */
29 | tcgetattr(1, &nstate); /* get base of new state */
30 | cfmakeraw(&nstate);
31 | tcsetattr(1, TCSADRAIN, &nstate); /* set mode */
32 | }
33 |
34 | /*
35 | * This function gets called just before we go back home to the command
36 | * interpreter. On VMS it puts the terminal back in a reasonable state.
37 | * Another no-operation on CPM.
38 | */
39 | void ttclose()
40 | {
41 | tcsetattr(1, TCSADRAIN, &ostate); // return to original mode
42 | }
43 |
44 | /*
45 | * Write a character to the display. On VMS, terminal output is buffered, and
46 | * we just put the characters in the big array, after checking for overflow.
47 | * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
48 | * MS-DOS (use the very very raw console output routine).
49 | */
50 | void ttputc(char c)
51 | {
52 | fputc(c, stdout);
53 | }
54 |
55 | /*
56 | * Flush terminal buffer. Does real work where the terminal output is buffered
57 | * up. A no-operation on systems where byte at a time terminal I/O is done.
58 | */
59 | void ttflush()
60 | {
61 | fflush(stdout);
62 | }
63 |
64 | /*
65 | * Read a character from the terminal, performing no editing and doing no echo
66 | * at all. More complex in VMS that almost anyplace else, which figures. Very
67 | * simple on CPM, because the system can do exactly what you want.
68 | */
69 | int ttgetc()
70 | {
71 | return fgetc(stdin);
72 | }
73 |
74 | /**************************
75 | * Return TRUE if there are unread chars ready in the input.
76 | */
77 |
78 | int ttkeysininput()
79 | {
80 | int n;
81 | ioctl(0, FIONREAD, &n);
82 | return n != 0;
83 | }
84 |
85 | /**************************
86 | * Return when there are unread chars ready in the input.
87 | */
88 |
89 | void ttwaitkeys()
90 | {
91 | import core.sys.posix.sys.select;
92 | fd_set readfds;
93 | FD_ZERO(&readfds);
94 | FD_SET(0, &readfds);
95 | select(1, &readfds, null, null, null);
96 | }
97 |
98 | /******************************
99 | */
100 |
101 | void ttyield()
102 | {
103 | }
104 |
105 | int msm_init()
106 | {
107 | puts("\x1b[?1000h");
108 | return true;
109 | }
110 |
111 | void msm_term()
112 | {
113 | puts("\x1b[?1000l");
114 | }
115 |
116 | }
117 |
118 | int main()
119 | {
120 | printf("type 'x' to exit\n");
121 | ttopen();
122 | msm_init();
123 | while (1)
124 | {
125 | int c = ttgetc();
126 | if (c > ' ' && c <= '~')
127 | printf("c = '%c' x%02x\n\r", c, c);
128 | else
129 | printf("c = x%02x\n\r", c);
130 | if (c == 'x')
131 | break;
132 | }
133 | msm_term();
134 | ttclose();
135 | return 0;
136 | }
137 |
--------------------------------------------------------------------------------
/src/med/url.d:
--------------------------------------------------------------------------------
1 |
2 | import core.stdc.stdio;
3 | import core.stdc.ctype;
4 |
5 | /*********************************
6 | * Determine if c is a valid URL character.
7 | */
8 | int isURLchar(char c)
9 | {
10 | if (isalnum(c))
11 | return 1;
12 | switch (c)
13 | {
14 | case '-':
15 | case '_':
16 | case '?':
17 | case '=':
18 | case '%':
19 | case '&':
20 | case '/':
21 | case '+':
22 | case '#':
23 | case '~':
24 | case '.':
25 | case ':':
26 | return 1;
27 |
28 | default:
29 | return 0;
30 | }
31 | }
32 |
33 | /******************************
34 | * Determine if string s of length is the start of a URL.
35 | * Returns:
36 | * 0 means not a URL, >0 gives the length of the URL
37 | */
38 | size_t isURL(const(char)[] s)
39 | {
40 | /* Must start with one of:
41 | * http://
42 | * https://
43 | */
44 |
45 | if (s.length < 9 || s[6] != '/')
46 | return 0;
47 |
48 | //writefln("isURL(%s)", s);
49 |
50 | if (!((s[0] == 'h' || s[0] == 'H') &&
51 | (s[1] == 't' || s[1] == 'T') &&
52 | (s[2] == 't' || s[2] == 'T') &&
53 | (s[3] == 'p' || s[3] == 'P')))
54 | return 0;
55 |
56 | size_t i;
57 | if (s[4] == ':' && s[5] == '/')
58 | i = 7;
59 | else if ((s[4] == 's' || s[4] == 'S') && s[5] == ':' && s[7] == '/')
60 | i = 8;
61 | else
62 | return 0;
63 |
64 | size_t lastdot;
65 | for (; i < s.length; i++)
66 | {
67 | auto c = s[i];
68 | if (isalnum(c))
69 | continue;
70 | if (c == '-' || c == '_' || c == '?' ||
71 | c == '=' || c == '%' || c == '&' ||
72 | c == '/' || c == '+' || c == '#' ||
73 | c == '~')
74 | continue;
75 | if (c == '.')
76 | {
77 | lastdot = i;
78 | continue;
79 | }
80 | break;
81 | }
82 | if (!lastdot)
83 | return 0;
84 |
85 | return i;
86 | }
87 |
88 |
89 | /****************************************************
90 | * Determine if index is in a URL or not.
91 | */
92 | int inURL(const(char)[] s, size_t index)
93 | {
94 | if (s.length < 9 || !isURLchar(s[index]))
95 | return 0;
96 |
97 | size_t i;
98 | size_t end = s.length - 9;
99 | if (index < end)
100 | end = index + 1;
101 | for (i = 0; i < end; ++i)
102 | {
103 | size_t j = isURL(s[i .. s.length]);
104 | if (j)
105 | {
106 | if (i <= index && index < i + j)
107 | return 1;
108 | i = i + j - 1;
109 | }
110 | }
111 | return 0;
112 | }
113 |
114 |
115 | /************************************************
116 | * Determine URL that index is in.
117 | * Return slice of s, null if not in a URL.
118 | */
119 |
120 | inout(char)[] getURL(inout(char)[] s, size_t index)
121 | {
122 | //printf("\ngetURL() '%.*s' \n", cast(int)s.length, s.ptr);
123 | for (size_t i = 0; i <= index; ++i)
124 | {
125 | size_t j = isURL(s[i .. s.length]);
126 | if (j)
127 | {
128 | if (i <= index && index < i + j)
129 | {
130 | return s[i .. i + j];
131 | }
132 | i = i + j - 1;
133 | }
134 | }
135 | return null;
136 | }
137 |
--------------------------------------------------------------------------------
/src/med/utf.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://dlang.org
7 | * This program is in the public domain.
8 | * https://github.com/DigitalMars/med/blob/master/src/med/uni.d
9 | */
10 |
11 | /******************************************
12 | * Decode Unicode character from UTF-8 string.
13 | * Advance index to be past decoded character.
14 | * Treat errors as if the first code unit is valid.
15 | * Params:
16 | * s = UTF-8 string to decode
17 | * index = index into s[] to start decoding, index is updated on return
18 | * Returns:
19 | * decoded character
20 | */
21 | dchar decodeUTF8(const(char)[] s, ref size_t index)
22 | {
23 | const i = index;
24 | const c = s[i];
25 | if (c <= 0x7F)
26 | {
27 | Lerr:
28 | index = i + 1;
29 | return c;
30 | }
31 |
32 | /* The following encodings are valid, except for the 5 and 6 byte
33 | * combinations:
34 | * 0xxxxxxx
35 | * 110xxxxx 10xxxxxx
36 | * 1110xxxx 10xxxxxx 10xxxxxx
37 | * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
38 | * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
39 | * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
40 | */
41 | uint n;
42 | for (n = 1; ; ++n)
43 | {
44 | if (n > 4)
45 | goto Lerr; // only do the first 4 of 6 encodings
46 | if (((c << n) & 0x80) == 0)
47 | {
48 | if (n == 1)
49 | goto Lerr;
50 | break;
51 | }
52 | }
53 |
54 | // Pick off (7 - n) significant bits of first byte of octet
55 | auto V = cast(dchar)(c & ((1 << (7 - n)) - 1));
56 |
57 | if (i + (n - 1) >= s.length)
58 | goto Lerr; // off end of string
59 |
60 | /* The following combinations are overlong, and illegal:
61 | * 1100000x (10xxxxxx)
62 | * 11100000 100xxxxx (10xxxxxx)
63 | * 11110000 1000xxxx (10xxxxxx 10xxxxxx)
64 | * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
65 | * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
66 | */
67 | const c2 = s[i + 1];
68 | if ((c & 0xFE) == 0xC0 ||
69 | (c == 0xE0 && (c2 & 0xE0) == 0x80) ||
70 | (c == 0xF0 && (c2 & 0xF0) == 0x80) ||
71 | (c == 0xF8 && (c2 & 0xF8) == 0x80) ||
72 | (c == 0xFC && (c2 & 0xFC) == 0x80))
73 | goto Lerr; // overlong combination
74 |
75 | for (uint j = 1; j != n; ++j)
76 | {
77 | const u = s[i + j];
78 | if ((u & 0xC0) != 0x80)
79 | goto Lerr; // trailing bytes are 10xxxxxx
80 | V = (V << 6) | (u & 0x3F);
81 | }
82 | if (!isValidDchar(V))
83 | goto Lerr;
84 | index = i + n;
85 | return V;
86 | }
87 |
88 | bool isValidDchar(dchar c)
89 | {
90 | return c < 0xD800 ||
91 | (c > 0xDFFF && c <= 0x10FFFF && c != 0xFFFE && c != 0xFFFF);
92 | }
93 |
94 | /********************************************
95 | * Backup in string. The reverse of decodeUTF8().
96 | */
97 |
98 | dchar decodeUTF8back(const(char)[] s, ref size_t index)
99 | {
100 | const i = index;
101 | if (!i)
102 | return 0;
103 |
104 | const c = s[i];
105 | if (c <= 0x7F)
106 | {
107 | Lerr:
108 | index = i - 1;
109 | return c;
110 | }
111 |
112 | uint n;
113 | for (size_t j = i; 1; )
114 | {
115 | if (j == 1 || i - j == 4)
116 | goto Lerr;
117 | --j;
118 | auto u = s[j];
119 | if (u <= 0x7F)
120 | goto Lerr;
121 | if ((u & 0xC0) == 0xC0)
122 | {
123 | index = j;
124 | return 0;
125 | }
126 | }
127 | assert(0);
128 | }
129 |
130 | enum dchar replacementDchar = '\uFFFD';
131 |
132 | char[] toUTF8(return out char[4] buf, dchar c) nothrow @nogc @safe
133 | {
134 | if (c <= 0x7F)
135 | {
136 | buf[0] = cast(char)c;
137 | return buf[0 .. 1];
138 | }
139 | else if (c <= 0x7FF)
140 | {
141 | buf[0] = cast(char)(0xC0 | (c >> 6));
142 | buf[1] = cast(char)(0x80 | (c & 0x3F));
143 | return buf[0 .. 2];
144 | }
145 | else if (c <= 0xFFFF)
146 | {
147 | if (c >= 0xD800 && c <= 0xDFFF)
148 | c = replacementDchar;
149 |
150 | L3:
151 | buf[0] = cast(char)(0xE0 | (c >> 12));
152 | buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
153 | buf[2] = cast(char)(0x80 | (c & 0x3F));
154 | return buf[0 .. 3];
155 | }
156 | else
157 | {
158 | if (c > 0x10FFFF)
159 | {
160 | c = replacementDchar;
161 | goto L3;
162 | }
163 |
164 | buf[0] = cast(char)(0xF0 | (c >> 18));
165 | buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
166 | buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
167 | buf[3] = cast(char)(0x80 | (c & 0x3F));
168 | return buf[0 .. 4];
169 | }
170 | }
171 |
172 |
--------------------------------------------------------------------------------
/src/med/window.d:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* This version of microEmacs is based on the public domain C
4 | * version written by Dave G. Conroy.
5 | * The D programming language version is written by Walter Bright.
6 | * http://www.digitalmars.com/d/
7 | * This program is in the public domain.
8 | */
9 |
10 |
11 | /*
12 | * Window management. Some of the functions are internal, and some are
13 | * attached to keys that the user actually types.
14 | */
15 |
16 | module window;
17 |
18 | import core.memory;
19 | import std.string;
20 |
21 | import ed;
22 | import buffer;
23 | import line;
24 | import main;
25 | import terminal;
26 | import display;
27 |
28 | /*
29 | * There is a window structure allocated for every active display window. The
30 | * windows are kept in a big list, in top to bottom screen order, with the
31 | * listhead at "wheadp". Each window contains its own values of dot and mark.
32 | * The flag field contains some bits that are set by commands to guide
33 | * redisplay; although this is a bit of a compromise in terms of decoupling,
34 | * the full blown redisplay is just too expensive to run for every input
35 | * character.
36 | */
37 | struct WINDOW {
38 | BUFFER* w_bufp; /* Buffer displayed in window */
39 | LINE* w_linep; /* Top line in the window */
40 | LINE* w_dotp; /* Line containing "." */
41 | int w_doto; /* Byte offset for "." */
42 | LINE* w_markp; /* Line containing "mark" */
43 | int w_marko; /* Byte offset for "mark" */
44 | int w_toprow; /* Origin 0 top row of window */
45 | int w_ntrows; /* # of rows of text in window */
46 | int w_force; /* If NZ, forcing row. */
47 | ubyte w_flag; /* Flags. */
48 | int w_startcol; /* starting column */
49 | }
50 |
51 | enum
52 | {
53 | WFFORCE = 0x01, /* Window needs forced reframe */
54 | WFMOVE = 0x02, /* Movement from line to line */
55 | WFEDIT = 0x04, /* Editing within a line */
56 | WFHARD = 0x08, /* Better do a full display */
57 | WFMODE = 0x10, /* Update mode line. */
58 | }
59 |
60 | __gshared WINDOW*[] windows;
61 |
62 | __gshared WINDOW* winSearchPat; // the window with highlighted search results
63 |
64 | /* !=0 means marking */
65 | bool window_marking(WINDOW* wp) { return wp.w_markp != null; }
66 |
67 |
68 | /*************************************
69 | * Reposition dot in the current window to line "n". If the argument is
70 | * positive, it is that line. If it is negative it is that line from the
71 | * bottom. If it is 0 the window is centered (this is what the standard
72 | * redisplay code does). With no argument it defaults to 1. Bound to M-!.
73 | * Because of the default, it works like in Gosling.
74 | */
75 |
76 | int window_reposition(bool f, int n)
77 | {
78 | curwp.w_force = n;
79 | curwp.w_flag |= WFFORCE;
80 | return (TRUE);
81 | }
82 |
83 | /*
84 | * Refresh the screen. With no argument, it just does the refresh. With an
85 | * argument it recenters "." in the current window. Bound to "C-L".
86 | */
87 | int window_refresh(bool f, int n)
88 | {
89 | if (f == FALSE)
90 | sgarbf = TRUE;
91 | else
92 | {
93 | curwp.w_force = 0; /* Center dot. */
94 | curwp.w_flag |= WFFORCE;
95 | }
96 |
97 | return (TRUE);
98 | }
99 |
100 | /*
101 | * The command make the next window (next => down the screen) the current
102 | * window. There are no real errors, although the command does nothing if
103 | * there is only 1 window on the screen. Bound to "C-X C-N".
104 | */
105 | int window_next(bool f, int n)
106 | {
107 | foreach (i, wp; windows)
108 | {
109 | if (wp == curwp)
110 | {
111 | i = i + 1;
112 | if (i == windows.length)
113 | i = 0;
114 | curwp = windows[i];
115 | curbp = curwp.w_bufp;
116 | return TRUE;
117 | }
118 | }
119 | return FALSE;
120 | }
121 |
122 | /*
123 | * This command makes the previous window (previous => up the screen) the
124 | * current window. There arn't any errors, although the command does not do a
125 | * lot if there is 1 window.
126 | */
127 | int window_prev(bool f, int n)
128 | {
129 | foreach (i, wp; windows)
130 | {
131 | if (wp == curwp)
132 | {
133 | if (i == 0)
134 | i = windows.length;
135 | i--;
136 | curwp = windows[i];
137 | curbp = curwp.w_bufp;
138 | return TRUE;
139 | }
140 | }
141 | return FALSE;
142 | }
143 |
144 | /*
145 | * This command moves the current window down by "arg" lines. Recompute the
146 | * top line in the window. The move up and move down code is almost completely
147 | * the same; most of the work has to do with reframing the window, and picking
148 | * a new dot. We share the code by having "move down" just be an interface to
149 | * "move up". Magic. Bound to "C-X C-N".
150 | */
151 | int window_mvdn(bool f, int n)
152 | {
153 | return window_mvup(f, -n);
154 | }
155 |
156 | /*
157 | * Move the current window up by "arg" lines. Recompute the new top line of
158 | * the window. Look to see if "." is still on the screen. If it is, you win.
159 | * If it isn't, then move "." to center it in the new framing of the window
160 | * (this command does not really move "."; it moves the frame). Bound to
161 | * "C-X C-P".
162 | */
163 | int window_mvup(bool f, int n)
164 | {
165 | LINE *lp;
166 | int i;
167 |
168 | lp = curwp.w_linep;
169 |
170 | if (n < 0)
171 | {
172 | while (n++ && lp!=curbp.b_linep)
173 | lp = lforw(lp);
174 | }
175 | else
176 | {
177 | while (n-- && lback(lp)!=curbp.b_linep)
178 | lp = lback(lp);
179 | }
180 |
181 | curwp.w_linep = lp; /* new top line of window */
182 | curwp.w_flag |= WFHARD; /* Mode line is OK. */
183 |
184 | for (i = 0; i < curwp.w_ntrows; ++i)
185 | {
186 | if (lp == curwp.w_dotp)
187 | return (TRUE);
188 | if (lp == curbp.b_linep)
189 | break;
190 | lp = lforw(lp);
191 | }
192 |
193 | lp = curwp.w_linep;
194 | i = curwp.w_ntrows/2;
195 |
196 | while (i-- && lp != curbp.b_linep)
197 | lp = lforw(lp);
198 |
199 | curwp.w_dotp = lp;
200 | curwp.w_doto = 0;
201 | return (TRUE);
202 | }
203 |
204 | /*
205 | * This command makes the current window the only window on the screen. Bound
206 | * to "C-X 1". Try to set the framing so that "." does not have to move on the
207 | * display. Some care has to be taken to keep the values of dot and mark in
208 | * the buffer structures right if the destruction of a window makes a buffer
209 | * become undisplayed.
210 | */
211 | int window_only(bool f, int n)
212 | {
213 | foreach (wp; windows)
214 | {
215 | if (wp != curwp)
216 | {
217 | if (--wp.w_bufp.b_nwnd == 0) {
218 | wp.w_bufp.b_dotp = wp.w_dotp;
219 | wp.w_bufp.b_doto = wp.w_doto;
220 | wp.w_bufp.b_markp = wp.w_markp;
221 | wp.w_bufp.b_marko = wp.w_marko;
222 | }
223 | if (winSearchPat == wp)
224 | winSearchPat = null;
225 | //delete wp;
226 | core.memory.GC.free(wp);
227 | }
228 | }
229 | windows = windows[0 .. 1];
230 | windows[0] = curwp;
231 |
232 | auto lp = curwp.w_linep;
233 | auto i = curwp.w_toprow;
234 | while (i!=0 && lback(lp)!=curbp.b_linep) {
235 | --i;
236 | lp = lback(lp);
237 | }
238 | curwp.w_toprow = 0;
239 | curwp.w_ntrows = term.t_nrow - 2;
240 | curwp.w_linep = lp;
241 | curwp.w_flag |= WFMODE|WFHARD;
242 | return (TRUE);
243 | }
244 |
245 | /*
246 | * Split the current window. A window smaller than 3 lines cannot be split.
247 | * The only other error that is possible is a "malloc" failure allocating the
248 | * structure for the new window. Bound to "C-X 2".
249 | */
250 | int window_split(bool f, int n)
251 | {
252 | LINE *lp;
253 | int ntru;
254 | int ntrl;
255 | int ntrd;
256 | WINDOW *wp1;
257 | WINDOW *wp2;
258 |
259 | if (curwp.w_ntrows < 3) {
260 | mlwrite("Cannot split a %d line window", curwp.w_ntrows);
261 | return (FALSE);
262 | }
263 | auto wp = new WINDOW;
264 | ++curbp.b_nwnd; /* Displayed twice. */
265 | wp.w_bufp = curbp;
266 | wp.w_dotp = curwp.w_dotp;
267 | wp.w_doto = curwp.w_doto;
268 | wp.w_markp = curwp.w_markp;
269 | wp.w_marko = curwp.w_marko;
270 | ntru = (curwp.w_ntrows-1) / 2; /* Upper size */
271 | ntrl = (curwp.w_ntrows-1) - ntru; /* Lower size */
272 | lp = curwp.w_linep;
273 | ntrd = 0;
274 | while (lp != curwp.w_dotp) {
275 | ++ntrd;
276 | lp = lforw(lp);
277 | }
278 | lp = curwp.w_linep;
279 | if (ntrd <= ntru) { /* Old is upper window. */
280 | if (ntrd == ntru) /* Hit mode line. */
281 | lp = lforw(lp);
282 | curwp.w_ntrows = ntru;
283 | // Insert wp after curwp
284 | foreach (i, w; windows)
285 | { if (w == curwp)
286 | {
287 | windows = windows[0 .. i + 1] ~ wp ~ windows[i + 1 .. $];
288 | break;
289 | }
290 | }
291 | wp.w_toprow = curwp.w_toprow+ntru+1;
292 | wp.w_ntrows = ntrl;
293 | } else { /* Old is lower window */
294 | // Insert wp before curwp
295 | foreach (i, w; windows)
296 | { if (w == curwp)
297 | {
298 | windows = windows[0 .. i] ~ wp ~ windows[i .. $];
299 | break;
300 | }
301 | }
302 |
303 | wp.w_toprow = curwp.w_toprow;
304 | wp.w_ntrows = ntru;
305 | ++ntru; /* Mode line. */
306 | curwp.w_toprow += ntru;
307 | curwp.w_ntrows = ntrl;
308 | while (ntru--)
309 | lp = lforw(lp);
310 | }
311 | curwp.w_linep = lp; /* Adjust the top lines */
312 | wp.w_linep = lp; /* if necessary. */
313 | curwp.w_flag |= WFMODE|WFHARD;
314 | wp.w_flag |= WFMODE|WFHARD;
315 | return (TRUE);
316 | }
317 |
318 | /*
319 | * Enlarge the current window. Find the window that loses space. Make sure it
320 | * is big enough. If so, hack the window descriptions, and ask redisplay to do
321 | * all the hard work. You don't just set "force reframe" because dot would
322 | * move. Bound to "C-X Z".
323 | */
324 | int window_enlarge(bool f, int n)
325 | {
326 | WINDOW *adjwp;
327 | LINE *lp;
328 | bool prev;
329 |
330 | if (n < 0)
331 | return (window_shrink(f, -n));
332 |
333 | if (windows.length == 1) {
334 | mlwrite("Only one window");
335 | return (FALSE);
336 | }
337 |
338 | foreach (i, wp; windows)
339 | {
340 | if (wp == curwp)
341 | {
342 | if (i == windows.length - 1)
343 | {
344 | adjwp = windows[i - 1];
345 | prev = true;
346 | }
347 | else
348 | {
349 | adjwp = windows[i + 1];
350 | prev = false;
351 | }
352 | break;
353 | }
354 | }
355 |
356 | if (adjwp.w_ntrows <= n) {
357 | mlwrite("Impossible enlarge change");
358 | return (FALSE);
359 | }
360 | if (!prev) { // Shrink below.
361 | lp = adjwp.w_linep;
362 | for (int i=0; i 0)
113 | {
114 | L1:
115 | col = 0;
116 | lasti = 0;
117 | inword = 0;
118 | for (i = 0; i < llength(curwp.w_dotp); i++)
119 | {
120 | c = lgetc(curwp.w_dotp, i);
121 | if (c == ' ' || c == '\t')
122 | {
123 | if (inword)
124 | lasti = i;
125 | inword = 0;
126 | }
127 | else
128 | {
129 | inword = 1;
130 | }
131 | col = getcol(curwp.w_dotp, i);
132 | if (col >= term.t_ncol && lasti)
133 | {
134 | if (!forwchar(0, lasti - curwp.w_doto))
135 | goto err;
136 | if (!random_newline(0,1))
137 | goto err;
138 |
139 | /* Remove leading whitespace from new line */
140 | while (1)
141 | {
142 | if (!llength(curwp.w_dotp))
143 | break;
144 | c = lgetc(curwp.w_dotp, 0);
145 | if (c == ' ' || c == '\t')
146 | {
147 | if (!random_forwdel(0, 1))
148 | goto err;
149 | }
150 | else
151 | break;
152 | }
153 |
154 | /* Match indenting of original line (oldp) */
155 | oldp = lback(curwp.w_dotp);
156 | for (j = 0; j < llength(oldp); j++)
157 | {
158 | c = lgetc(oldp, j);
159 | if (c == ' ' || c == '\t')
160 | {
161 | if (!line_insert(1, c))
162 | goto err;
163 | }
164 | else
165 | break;
166 | }
167 |
168 | goto L1;
169 | }
170 | }
171 | if (!forwline(0, 1))
172 | goto err;
173 | }
174 | if (window_marking(curwp))
175 | {
176 | if (dotosave > llength(dotpsave))
177 | dotosave = llength(dotpsave);
178 | curwp.w_dotp = dotpsave;
179 | curwp.w_doto = dotosave;
180 | }
181 | return true;
182 |
183 | err:
184 | return false;
185 | }
186 |
187 | /*************************
188 | * Select word that the cursor is on.
189 | */
190 |
191 | int word_select(bool f, int n)
192 | {
193 | int inw;
194 | int s;
195 |
196 | inw = inword();
197 | do
198 | s = backchar(false, 1);
199 | while (s && inword() == inw);
200 |
201 | return s &&
202 | forwchar(false,1) &&
203 | basic_setmark(false,1) &&
204 | word_forw(f,n);
205 | }
206 |
207 | /******************************
208 | * Select line that the cursor is on.
209 | */
210 |
211 | int word_lineselect(bool f, int n)
212 | {
213 | return (curwp.w_doto == 0 || gotobol(false,1)) &&
214 | basic_setmark(false,1) &&
215 | forwline(f,n);
216 | }
217 |
218 | /*
219 | * Move the cursor backward by "n" words. All of the details of motion are
220 | * performed by the "backchar" and "forwchar" routines. Error if you try to
221 | * move beyond the buffers.
222 | */
223 | int word_back(bool f, int n)
224 | {
225 | if (n < 0)
226 | return (word_forw(f, -n));
227 | if (backchar(false, 1) == false)
228 | return (false);
229 | while (n--) {
230 | auto inw = inword();
231 | do
232 | if (backchar(false, 1) == false)
233 | return (false);
234 | while (inword() == inw);
235 | }
236 | return (forwchar(false, 1));
237 | }
238 |
239 | /*
240 | * Move the cursor forward by the specified number of words. All of the motion
241 | * is done by "forwchar". Error if you try and move beyond the buffer's end.
242 | */
243 | int word_forw(bool f, int n)
244 | {
245 | if (n < 0)
246 | return (word_back(f, -n));
247 | while (n--) {
248 | auto inw = inword();
249 | do
250 | if (forwchar(false, 1) == false)
251 | return (false);
252 | while (inword() == inw);
253 | }
254 | return (true);
255 | }
256 |
257 | /*
258 | * Move the cursor forward by the specified number of words. As you move,
259 | * convert any characters to upper case. Error if you try and move beyond the
260 | * end of the buffer. Bound to "M-U".
261 | */
262 | int word_upper(bool f, int n)
263 | {
264 | return word_setcase(f,n,0);
265 | }
266 |
267 | /*
268 | * Move the cursor forward by the specified number of words. As you move
269 | * convert characters to lower case. Error if you try and move over the end of
270 | * the buffer. Bound to "M-L".
271 | */
272 | int word_lower(bool f, int n)
273 | {
274 | return word_setcase(f,n,1);
275 | }
276 |
277 | /*************************
278 | * Move the cursor forward by the specified number of words. As you move
279 | * convert the first character of the word to upper case, and subsequent
280 | * characters to lower case. Error if you try and move past the end of the
281 | * buffer. Bound to "M-C".
282 | */
283 |
284 | int capword(bool f, int n)
285 | {
286 | return word_setcase(f,n,2);
287 | }
288 |
289 | private int word_setcase(bool f, int n, int flag)
290 | {
291 | char c;
292 |
293 | if (n < 0)
294 | return (false);
295 | while (n--) {
296 | while (inword() == false) {
297 | if (forwchar(false, 1) == false)
298 | return (false);
299 | }
300 | if (flag == 2 && inword() != false) {
301 | c = lgetc(curwp.w_dotp, curwp.w_doto);
302 | if (isLower(c))
303 | { c -= 'a'-'A';
304 | lputc(curwp.w_dotp, curwp.w_doto, c);
305 | line_change(WFHARD);
306 | }
307 | if (forwchar(false, 1) == false)
308 | return (false);
309 | }
310 | while (inword() != false) {
311 | c = lgetc(curwp.w_dotp, curwp.w_doto);
312 | final switch (flag)
313 | { case 0:
314 | if (isLower(c)) {
315 | c -= 'a'-'A';
316 | goto L1;
317 | }
318 | break;
319 | case 1:
320 | case 2:
321 | if (isUpper(c)) {
322 | c += 'a'-'A';
323 | L1: lputc(curwp.w_dotp, curwp.w_doto, c);
324 | line_change(WFHARD);
325 | }
326 | break;
327 | }
328 | if (forwchar(false, 1) == false)
329 | return (false);
330 | }
331 | }
332 | return (true);
333 | }
334 |
335 | /*
336 | * Kill forward by "n" words. Remember the location of dot. Move forward by
337 | * the right number of words. Put dot back where it was and issue the kill
338 | * command for the right number of characters. Bound to "M-D".
339 | */
340 | int delfword(bool f, int n)
341 | {
342 | int size;
343 | LINE* dotp;
344 | int doto;
345 |
346 | if (n < 0)
347 | return (false);
348 | dotp = curwp.w_dotp;
349 | doto = curwp.w_doto;
350 | size = 0;
351 | while (n--) {
352 | while (inword() == false) {
353 | if (forwchar(false, 1) == false)
354 | return (false);
355 | ++size;
356 | }
357 | while (inword() != false) {
358 | if (forwchar(false, 1) == false)
359 | return (false);
360 | ++size;
361 | }
362 | }
363 | curwp.w_dotp = dotp;
364 | curwp.w_doto = doto;
365 | return (line_delete(size, true));
366 | }
367 |
368 | /*
369 | * Kill backwards by "n" words. Move backwards by the desired number of words,
370 | * counting the characters. When dot is finally moved to its resting place,
371 | * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
372 | */
373 | int delbword(bool f, int n)
374 | {
375 | int size;
376 |
377 | if (n < 0)
378 | return (false);
379 | if (backchar(false, 1) == false)
380 | return (false);
381 | size = 0;
382 | while (n--) {
383 | while (inword() == false) {
384 | if (backchar(false, 1) == false)
385 | return (false);
386 | ++size;
387 | }
388 | while (inword() != false) {
389 | if (backchar(false, 1) == false)
390 | return (false);
391 | ++size;
392 | }
393 | }
394 | if (forwchar(false, 1) == false)
395 | return false;
396 | return line_delete(size, true);
397 | }
398 |
399 | /*
400 | * Return true if the character at dot is a character that is considered to be
401 | * part of a word. The word character list is hard coded. Should be setable.
402 | * This routine MUST return only a 1 or a 0.
403 | */
404 | bool inword()
405 | {
406 | if (curwp.w_doto == llength(curwp.w_dotp))
407 | return false;
408 | auto c = lgetc(curwp.w_dotp, curwp.w_doto);
409 | return (isAlphaNum(c) ||
410 | c=='$' || c=='_'); /* For identifiers */
411 | }
412 |
--------------------------------------------------------------------------------
/win32.mak:
--------------------------------------------------------------------------------
1 | #_ win32.mak
2 | # Build win32 version of microemacs
3 | # Needs Digital Mars D compiler to build, available free from:
4 | # http://www.digitalmars.com/d/
5 |
6 | DMD=dmd
7 | DEL=del
8 | S=src\med
9 | O=obj
10 | B=bin
11 |
12 | TARGET=med
13 |
14 | //DFLAGS=-g -Isrc/med $(CONF)
15 | DFLAGS=-O -Isrc/med $(CONF)
16 | LFLAGS=-L/map/co
17 | #DFLAGS=
18 | #LFLAGS=
19 |
20 | .d.obj :
21 | $(DMD) -c $(DFLAGS) $*
22 |
23 | SRC= $S\ed.d $S\basic.d $S\buffer.d $S\display.d $S\file.d $S\fileio.d $S\line.d \
24 | $S\random.d $S\region.d $S\search.d $S\spawn.d $S\terminal.d \
25 | $S\window.d $S\word.d $S\main.d $S\more.d $S\disprev.d \
26 | $S\termio.d $S\xterm.d $S\syntaxd.d $S\syntaxc.d $S\syntaxcpp.d \
27 | $S\tcap.d $S\console.d $S\mouse.d $S\disp.d $S\url.d $S\utf.d $S\regexp.d
28 |
29 |
30 | OBJ= $O\ed.obj $O\basic.obj $O\buffer.obj $O\display.obj $O\file.obj $O\fileio.obj $O\line.obj \
31 | $O\random.obj $O\region.obj $O\search.obj $O\spawn.obj $O\terminal.obj \
32 | $O\window.obj $O\word.obj $O\main.obj $O\more.obj $O\disprev.obj \
33 | $O\termio.obj $O\xterm.obj $O\syntaxd.obj $O\syntaxc.obj $O\syntaxcpp.obj \
34 | $O\tcap.obj $O\console.obj $O\mouse.obj $O\disp.obj $O\url.obj $O\utf.obj $O\regexp.obj
35 |
36 | SOURCE= $(SRC) win32.mak linux.mak me.html README.md
37 |
38 | all: $B\$(TARGET).exe
39 |
40 | #################################################
41 |
42 | $B\$(TARGET).exe : $(OBJ)
43 | $(DMD) -of$B\$(TARGET).exe $(OBJ) $(LFLAGS)
44 |
45 | $O\ed.obj: $S\ed.d
46 | $(DMD) -c $(DFLAGS) -od$O $S\ed.d
47 |
48 | $O\basic.obj: $S\basic.d
49 | $(DMD) -c $(DFLAGS) -od$O $S\basic.d
50 |
51 | $O\buffer.obj: $S\buffer.d
52 | $(DMD) -c $(DFLAGS) -od$O $S\buffer.d
53 |
54 | $O\console.obj: $S\console.d
55 | $(DMD) -c $(DFLAGS) -od$O $S\console.d
56 |
57 | $O\disp.obj: $S\disp.d
58 | $(DMD) -c $(DFLAGS) -od$O $S\disp.d
59 |
60 | $O\display.obj: $S\display.d
61 | $(DMD) -c $(DFLAGS) -od$O $S\display.d
62 |
63 | $O\file.obj: $S\file.d
64 | $(DMD) -c $(DFLAGS) -od$O $S\file.d
65 |
66 | $O\fileio.obj: $S\fileio.d
67 | $(DMD) -c $(DFLAGS) -od$O $S\fileio.d
68 |
69 | $O\line.obj: $S\line.d
70 | $(DMD) -c $(DFLAGS) -od$O $S\line.d
71 |
72 | $O\mouse.obj: $S\mouse.d
73 | $(DMD) -c $(DFLAGS) -od$O $S\mouse.d
74 |
75 | $O\random.obj: $S\random.d
76 | $(DMD) -c $(DFLAGS) -od$O $S\random.d
77 |
78 | $O\regexp.obj: $S\regexp.d
79 | $(DMD) -c $(DFLAGS) -od$O $S\regexp.d
80 |
81 | $O\region.obj: $S\region.d
82 | $(DMD) -c $(DFLAGS) -od$O $S\region.d
83 |
84 | $O\search.obj: $S\search.d
85 | $(DMD) -c $(DFLAGS) -od$O $S\search.d
86 |
87 | $O\spawn.obj: $S\spawn.d
88 | $(DMD) -c $(DFLAGS) -od$O $S\spawn.d
89 |
90 | $O\syntaxd.obj: $S\syntaxd.d
91 | $(DMD) -c $(DFLAGS) -od$O $S\syntaxd.d
92 |
93 | $O\syntaxc.obj: $S\syntaxc.d
94 | $(DMD) -c $(DFLAGS) -od$O $S\syntaxc.d
95 |
96 | $O\syntaxcpp.obj: $S\syntaxcpp.d
97 | $(DMD) -c $(DFLAGS) -od$O $S\syntaxcpp.d
98 |
99 | $O\terminal.obj: $S\terminal.d
100 | $(DMD) -c $(DFLAGS) -od$O $S\terminal.d
101 |
102 | $O\termio.obj: $S\termio.d
103 | $(DMD) -c $(DFLAGS) -od$O $S\termio.d
104 |
105 | $O\url.obj: $S\url.d
106 | $(DMD) -c $(DFLAGS) -od$O $S\url.d
107 |
108 | $O\utf.obj: $S\utf.d
109 | $(DMD) -c $(DFLAGS) -od$O $S\utf.d
110 |
111 | $O\window.obj: $S\window.d
112 | $(DMD) -c $(DFLAGS) -od$O $S\window.d
113 |
114 | $O\word.obj: $S\word.d
115 | $(DMD) -c $(DFLAGS) -od$O $S\word.d
116 |
117 | $O\main.obj: $S\main.d
118 | $(DMD) -c $(DFLAGS) -od$O $S\main.d
119 |
120 | $O\more.obj: $S\more.d
121 | $(DMD) -c $(DFLAGS) -od$O $S\more.d
122 |
123 | $O\disprev.obj: $S\disprev.d
124 | $(DMD) -c $(DFLAGS) -od$O $S\disprev.d
125 |
126 | $O\tcap.obj: $S\tcap.d
127 | $(DMD) -c $(DFLAGS) -od$O $S\tcap.d
128 |
129 | $O\xterm.obj: $S\xterm.d
130 | $(DMD) -c $(DFLAGS) -od$O $S\xterm.d
131 |
132 | ###################################
133 |
134 | clean:
135 | del $(OBJ) $B\$(TARGET).map
136 |
137 |
138 | tolf:
139 | tolf $(SOURCE)
140 |
141 |
142 | detab:
143 | detab $(SRC)
144 |
145 |
146 | zip: tolf detab
147 | $(DEL) me.zip
148 | zip32 me $(SOURCE)
149 |
150 |
151 | git: tolf detab win32.mak
152 | \putty\pscp -i c:\.ssh\colossus.ppk $(SRC) walter@mercury:dm/med/src/med
153 | \putty\pscp -i c:\.ssh\colossus.ppk win32.mak linux.mak me.html README.md walter@mercury:dm/med/
154 |
155 |
--------------------------------------------------------------------------------