Last active
June 17, 2022 03:15
-
-
Save ALANVF/79250fa7741021999d1401aab57d5b6c to your computer and use it in GitHub Desktop.
Text editor demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Red [ | |
Title: "Text editor" | |
Author: "ALANVF" | |
Date: 16-Jun-2022 | |
File: %text-editor.red | |
Needs: 'View | |
Purpose: { | |
Basic text editor | |
} | |
] | |
num-untitled: 0 | |
title-text: none | |
edited?: no | |
current-file: none | |
current-untitled: "Untitled" | |
confirm: func [ | |
msg [string!] | |
return: [logic!] | |
/local | |
result | |
][ | |
view compose/only [ | |
title "Confirm choice" | |
on-close [ | |
result: none | |
] | |
below center | |
text center (msg) | |
panel [ | |
button 50 "Yes" with [set-focus self] [ | |
result: yes | |
unview | |
] | |
button 50 "No" [ | |
result: no | |
unview | |
] | |
] | |
] | |
return result | |
] | |
save-current: does [ | |
if none? current-file [ | |
current-file: request-file/save/file rejoin [current-untitled ".txt"] | |
] | |
unless none? current-file [ | |
write current-file editor/text | |
] | |
] | |
ask-to-save: [ | |
switch confirm "Do you want to save first?" [ | |
#[true] [ save-current ] | |
#[none] [ exit ] | |
] | |
] | |
do-new: does [ | |
if edited? [ | |
do ask-to-save | |
edited?: no | |
] | |
clear editor/text | |
num-untitled: num-untitled + 1 | |
append clear title-text current-untitled: rejoin ["Untitled" num-untitled] | |
] | |
do-open: does [ | |
if edited? [ | |
do ask-to-save | |
unless none? current-file [ | |
edited?: no | |
] | |
] | |
unless none? current-file: request-file [ | |
insert clear editor/text read current-file | |
append clear title-text to-local-file current-file | |
] | |
] | |
do-save: does [ | |
if edited? [ | |
save-current | |
unless none? current-file [ | |
remove back tail title-text | |
edited?: no | |
] | |
] | |
] | |
do-save-as: does [ | |
current-file: request-file/save/file | |
either none? current-file [rejoin [current-untitled ".txt"]][current-file] | |
unless none? current-file [ | |
write current-file editor/text | |
if edited? [ | |
append clear title-text to-local-file current-file | |
edited?: no | |
] | |
] | |
] | |
do-exit: does [ | |
if edited? [ | |
do ask-to-save | |
remove back tail title-text | |
edited?: no | |
] | |
unview/all | |
] | |
find-text: func [ | |
text [string!] | |
pos [integer!] | |
case? [logic!] | |
reverse? [logic!] | |
return: [pair! none!] | |
/local | |
found | |
][ | |
found: either case? [ | |
either reverse? [ | |
find/reverse/case at editor/text pos text | |
][ | |
find/case at editor/text pos text | |
] | |
][ | |
either reverse? [ | |
find/reverse at editor/text pos text | |
][ | |
find at editor/text pos text | |
] | |
] | |
either none? found [none][ | |
as-pair | |
index? found | |
(index? found) + (length? text) - 1 | |
] | |
] | |
no-more-matches: func [ | |
title [string!] | |
top-or-bottom [string! none!] | |
/local text | |
][ | |
text: either none? top-or-bottom [ | |
"No more matches available" | |
][ | |
rejoin ["No more matches, starting from the " top-or-bottom] | |
] | |
view compose [ | |
title (title) | |
below center | |
text (text) | |
button focus "Ok" [ unview ] | |
] | |
] | |
do-find: has [to-find next-btn prev-btn selection current-pos found][ | |
current-pos: 1 | |
view [ | |
title "Find text" | |
below left | |
panel [ | |
across middle | |
text 50 center "Find:" | |
to-find: field 150 "" with [ | |
set-focus self | |
selection: editor/selected | |
unless none? selection [ | |
text: copy/part (at editor/text selection/x) (selection/y - selection/x) | |
selected: as-pair 1 length? text | |
current-pos: selection/x | |
] | |
] | |
] | |
panel [ | |
across middle | |
next-btn: button "Find next" [ | |
found: find-text to-find/text current-pos case-check/data no | |
if none? found [ | |
no-more-matches "Find text" "top" | |
current-pos: 1 | |
found: find-text to-find/text current-pos case-check/data no | |
] | |
unless none? found [ | |
editor/selected: found | |
current-pos: found/y | |
] | |
] | |
prev-btn: button "Find previous" [ | |
found: find-text to-find/text current-pos case-check/data yes | |
if none? found [ | |
no-more-matches "Find text" "bottom" | |
current-pos: length? editor/text | |
found: find-text to-find/text current-pos case-check/data yes | |
] | |
unless none? found [ | |
editor/selected: found | |
current-pos: found/x | |
;-- if we are on the first match, don't try matching it again | |
if none? find-text to-find/text current-pos case-check/data yes [ | |
current-pos: found/y | |
] | |
] | |
] | |
case-check: check "Match case" false | |
] | |
] | |
] | |
do-replace: has [ | |
to-find replace-with next-btn prev-btn replace-btn replace-all-btn | |
selection current-pos found find-replace num-replaced | |
][ | |
current-pos: 1 | |
find-replace: [ | |
found: find-text to-find/text current-pos case-check/data no | |
if none? found [ | |
current-pos: 0 | |
found: find-text to-find/text current-pos case-check/data no | |
either none? found [ | |
no-more-matches "Replace text" none | |
][ | |
no-more-matches "Replace text" "top" | |
] | |
] | |
unless none? found [ | |
editor/selected: found | |
current-pos: found/x | |
] | |
] | |
view [ | |
title "Replace text" | |
below left | |
panel [ | |
across middle | |
text 50 center "Find:" | |
to-find: field 150 "" with [ | |
selection: editor/selected | |
either none? selection [ | |
set-focus self | |
][ | |
text: copy/part (at editor/text selection/x) (selection/y - selection/x) | |
selected: as-pair 1 length? text | |
current-pos: selection/x | |
] | |
] | |
return | |
text 50 center "Replace:" | |
replace-with: field 150 "" with [ | |
unless none? selection [ | |
set-focus self | |
] | |
] | |
] | |
panel [ | |
across middle | |
next-btn: button "Find next" [ | |
found: find-text to-find/text current-pos case-check/data no | |
if none? found [ | |
no-more-matches "Replace text" "top" | |
current-pos: 1 | |
found: find-text to-find/text current-pos case-check/data no | |
] | |
unless none? found [ | |
editor/selected: found | |
current-pos: found/y | |
] | |
] | |
prev-btn: button "Find previous" [ | |
found: find-text to-find/text current-pos case-check/data yes | |
if none? found [ | |
no-more-matches "Replace text" "bottom" | |
current-pos: length? editor/text | |
found: find-text to-find/text current-pos case-check/data yes | |
] | |
unless none? found [ | |
editor/selected: found | |
current-pos: found/x | |
;-- if we are on the first match, don't try matching it again | |
if none? find-text to-find/text current-pos case-check/data yes [ | |
current-pos: found/y | |
] | |
] | |
] | |
] | |
panel [ | |
across middle | |
replace-btn: button "Replace" [ | |
if none? editor/selected [ do find-replace ] | |
unless none? selection: editor/selected [ | |
change/part | |
at editor/text selection/x | |
replace-with/text | |
at editor/text selection/y + 1 | |
current-pos: selection/x + length? replace-with/text | |
do find-replace | |
] | |
] | |
replace-all-btn: button "Replace all" [ | |
num-replaced: 0 | |
current-pos: 1 | |
while [not none? found: find-text to-find/text current-pos case-check/data no][ | |
change/part | |
at editor/text found/x | |
replace-with/text | |
at editor/text found/y + 1 | |
num-replaced: num-replaced + 1 | |
current-pos: found/x + length? replace-with/text | |
] | |
alert rejoin [ | |
num-replaced | |
" match" | |
either num-replaced = 1 [""]["es"] | |
" replaced" | |
] | |
] | |
case-check: check "Match case" false | |
] | |
] | |
] | |
view/flags [ | |
size 500x300 | |
title "Text editor - Untitled" | |
on-resizing [ | |
editor/size: face/size - 20x20 | |
] | |
on-menu [ | |
switch event/picked [ | |
new [ do-new ] | |
open [ do-open ] | |
save [ do-save ] | |
save-as [ do-save-as ] | |
exit [ do-exit ] | |
find [ do-find ] | |
replace [ do-replace ] | |
font [ | |
font: request-font | |
unless none? font [ | |
editor/font: font | |
] | |
] | |
] | |
] | |
on-close [ | |
if edited? [ | |
do ask-to-save | |
] | |
] | |
do [ | |
title-text: find/tail text " - " | |
menu: [ | |
"File" [ | |
"New Ctrl+N" new | |
"Open Ctrl+O" open | |
"Save Ctrl+S" save | |
"Save as Ctrl+Shift+S" save-as | |
--- | |
"Exit Ctrl+E" exit | |
] | |
"Edit" [ | |
"Find Ctrl+F" find | |
"Replace Ctrl+H" replace | |
] | |
"View" [ | |
"Choose font" font | |
] | |
] | |
] | |
editor: area "" on-key [ | |
case [ | |
event/ctrl? [ | |
switch/default event/key [ | |
#"^N" [ do-new ] | |
#"^O" [ do-open ] | |
#"^S" [ either event/shift? [do-save-as][do-save] ] | |
#"^E" [ do-exit ] | |
#"^F" [ do-find ] | |
#"^R" [ do-replace ] | |
; ignore these since they don't edit anything | |
#"^A" #"^C" [] | |
][ | |
unless edited? [ | |
edited?: yes | |
append title-text "*" | |
] | |
] | |
] | |
event/key = #"^[" [ | |
editor/selected: none | |
] | |
not edited? [ | |
edited?: yes | |
append title-text "*" | |
] | |
] | |
] | |
] [resize] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment