commit
4172db3259
18
README.md
18
README.md
|
@ -1,6 +1,6 @@
|
||||||
# rodo
|
# rodo
|
||||||
|
|
||||||
A minimal todo list program for people who live on the command line.
|
A minimal list manager for people who live on the command line.
|
||||||
|
|
||||||
# Screenshot
|
# Screenshot
|
||||||
|
|
||||||
|
@ -54,17 +54,17 @@ If you are using a single-file executable, create a wrapper as follows:
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
This readme will guide you through downloading, installing, and using the rodo
|
This readme will guide you through downloading, installing, and using the rodo
|
||||||
todo list program. It is intended for people who spend a lot of their time on the
|
list manager. It is intended for people who spend a lot of their time on the
|
||||||
command line and want a minimal todo list application.
|
command line and want a minimal list manager.
|
||||||
|
|
||||||
# Conventions used in this readme
|
# Conventions used in this readme
|
||||||
|
|
||||||
* Notes - Notes signify additional information
|
* **Note** - Notes signify additional information
|
||||||
* Tips - Tips signify an alternate procedure for completing a step
|
* **Tip**- Tips signify an alternate procedure for completing a step
|
||||||
* Cautions - Cautions signify that damage may occur
|
* **Caution** - Cautions signify that damage may occur
|
||||||
* Examples - Examples provide a visual reference of how a procedure would be carried out in the real world
|
* **Example** - Examples provide a visual reference of how a procedure would be carried out in the real world
|
||||||
* `Inline code` - Inline code signifies package names, filenames, or commands
|
* `Inline code` - Inline code signifies package names, filenames, or commands
|
||||||
* ```Code blocks``` - Code blocks signify file contents
|
* ```Code block``` - Code blocks signify file contents
|
||||||
|
|
||||||
# Platforms
|
# Platforms
|
||||||
|
|
||||||
|
@ -191,5 +191,5 @@ The examples below assume that you have [added rodo to your $PATH](#adding-rodo-
|
||||||
|
|
||||||
**Caution**: Changing the `config.rkt` file should be done at your own risk as it may break rodo's functionality
|
**Caution**: Changing the `config.rkt` file should be done at your own risk as it may break rodo's functionality
|
||||||
|
|
||||||
Settings such as the program name, directory, and the filename of the todo list
|
Settings such as the program name, directory, and the filename of the list
|
||||||
file can be changed by editing the `config.rkt` file.
|
file can be changed by editing the `config.rkt` file.
|
||||||
|
|
37
args.rkt
37
args.rkt
|
@ -2,45 +2,44 @@
|
||||||
|
|
||||||
(require (prefix-in config: "config.rkt")
|
(require (prefix-in config: "config.rkt")
|
||||||
(prefix-in init: "init.rkt")
|
(prefix-in init: "init.rkt")
|
||||||
|
(prefix-in file: racket/file)
|
||||||
(prefix-in messages: "messages.rkt")
|
(prefix-in messages: "messages.rkt")
|
||||||
(prefix-in utils: "utils.rkt"))
|
(prefix-in utils: "utils.rkt"))
|
||||||
|
|
||||||
(provide (all-defined-out))
|
(provide (all-defined-out))
|
||||||
|
|
||||||
(define (check-args args)
|
(define (check-args args)
|
||||||
(let ([args-length (vector-length args)])
|
(let ([args-length (length args)])
|
||||||
(cond
|
(cond
|
||||||
[(equal? args-length 0)
|
[(equal? args-length 0)
|
||||||
(utils:display-hash-ref messages:messages 'show-usage)]
|
(utils:display-hash-ref messages:messages 'show-usage)]
|
||||||
|
|
||||||
;; help
|
;; help-command
|
||||||
[(and (equal? args-length 1)
|
[(and (equal? args-length 1)
|
||||||
(member (vector-ref args 0) config:help-command))
|
(member (list-ref args 0) config:help-command))
|
||||||
(utils:display-hash-ref messages:messages 'show-help)]
|
(utils:display-hash-ref messages:messages 'show-help)]
|
||||||
|
|
||||||
;; init
|
;; initialize-command
|
||||||
[(and (equal? args-length 1)
|
[(and (equal? args-length 1)
|
||||||
(member (vector-ref args 0) config:initialize-command))
|
(member (list-ref args 0) config:initialize-command))
|
||||||
(init:initialize)]
|
(init:initialize)]
|
||||||
|
|
||||||
;; add
|
;; add-command
|
||||||
[(and (or (equal? args-length 2) (>= args-length 2))
|
[(and (or (equal? args-length 2) (>= args-length 2))
|
||||||
(member (vector-ref args 0) config:add-command))
|
(member (list-ref args 0) config:add-command))
|
||||||
(utils:add-item-to-list config:path-to-list-file args)]
|
(utils:add-item-to-list config:list-file args)]
|
||||||
|
|
||||||
;; ls
|
;; list-command
|
||||||
[(and (equal? args-length 1)
|
[(and (equal? args-length 1)
|
||||||
(member (vector-ref args 0) config:list-command))
|
(member (list-ref args 0) config:list-command))
|
||||||
(utils:show-list-from-file config:path-to-list-file)]
|
(utils:show-list-from-file config:list-file)]
|
||||||
|
|
||||||
;; rm
|
;; remove-command
|
||||||
[(and (equal? args-length 2)
|
[(and (equal? args-length 2)
|
||||||
(member (vector-ref args 0) config:remove-command)
|
(member (list-ref args 0) config:remove-command)
|
||||||
(real? (string->number (vector-ref args 1)))
|
(real? (string->number (list-ref args 1)))
|
||||||
(or (positive? (string->number (vector-ref args 1)))
|
(or (positive? (string->number (list-ref args 1)))
|
||||||
(zero? (string->number (vector-ref args 1))))
|
(zero? (string->number (list-ref args 1)))))
|
||||||
;; Length subtract one because the numbering starts at zero
|
(utils:remove-item-from-list args)]
|
||||||
(not (> (string->number (vector-ref args 1)) (sub1 (length (utils:file->string-list config:path-to-list-file))))))
|
|
||||||
(utils:remove-item-from-list config:path-to-list-file args)]
|
|
||||||
|
|
||||||
[else (utils:display-hash-ref messages:messages 'show-usage)])))
|
[else (utils:display-hash-ref messages:messages 'show-usage)])))
|
||||||
|
|
11
config.rkt
11
config.rkt
|
@ -1,7 +1,7 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
(provide (all-defined-out))
|
(provide (all-defined-out))
|
||||||
|
|
||||||
(define list-file "todo.txt")
|
(define file-name "list.txt")
|
||||||
(define program-name "rodo")
|
(define program-name "rodo")
|
||||||
|
|
||||||
(define program-directory
|
(define program-directory
|
||||||
|
@ -9,25 +9,30 @@
|
||||||
(expand-user-path
|
(expand-user-path
|
||||||
(string-append "~/." program-name "/"))))
|
(string-append "~/." program-name "/"))))
|
||||||
|
|
||||||
(define path-to-list-file
|
(define list-file
|
||||||
(string-append program-directory list-file))
|
(string-append program-directory file-name))
|
||||||
|
|
||||||
|
;; TODO: pluralize this value's name
|
||||||
(define help-command '("-h"
|
(define help-command '("-h"
|
||||||
"--help"
|
"--help"
|
||||||
"h"
|
"h"
|
||||||
"help"))
|
"help"))
|
||||||
|
|
||||||
|
;; TODO: pluralize this value's name
|
||||||
(define initialize-command '("init"
|
(define initialize-command '("init"
|
||||||
"create"
|
"create"
|
||||||
"start"
|
"start"
|
||||||
"begin"))
|
"begin"))
|
||||||
|
|
||||||
|
;; TODO: pluralize this value's name
|
||||||
(define add-command '("add"
|
(define add-command '("add"
|
||||||
"a"))
|
"a"))
|
||||||
|
|
||||||
|
;; TODO: pluralize this value's name
|
||||||
(define list-command '("ls"
|
(define list-command '("ls"
|
||||||
"list"))
|
"list"))
|
||||||
|
|
||||||
|
;; TODO: pluralize this value's name
|
||||||
(define remove-command '("rm"
|
(define remove-command '("rm"
|
||||||
"remove"
|
"remove"
|
||||||
"del"
|
"del"
|
||||||
|
|
10
init.rkt
10
init.rkt
|
@ -13,10 +13,10 @@
|
||||||
(cond [(member user-input (hash-ref messages:y/n 'yes))
|
(cond [(member user-input (hash-ref messages:y/n 'yes))
|
||||||
(begin
|
(begin
|
||||||
(utils:display-hash-ref messages:messages 'creating)
|
(utils:display-hash-ref messages:messages 'creating)
|
||||||
(utils:create-program-directory-700 config:program-directory)
|
(utils:create-directory-700 config:program-directory)
|
||||||
(utils:create-list-file-600 config:path-to-list-file)
|
(utils:create-file-600 config:list-file)
|
||||||
(if (and (utils:program-directory-exists?)
|
(if (and (directory-exists? config:program-directory)
|
||||||
(utils:list-file-exists?))
|
(file-exists? config:list-file))
|
||||||
(utils:display-hash-ref messages:messages 'successfully-created)
|
(utils:display-hash-ref messages:messages 'successfully-created)
|
||||||
(utils:display-hash-ref messages:messages 'creation-error)))]
|
(utils:display-hash-ref messages:messages 'creation-error)))]
|
||||||
[(member user-input (hash-ref messages:y/n 'no))
|
[(member user-input (hash-ref messages:y/n 'no))
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
(init-prompt messages:messages 'choose-y/n)])))
|
(init-prompt messages:messages 'choose-y/n)])))
|
||||||
|
|
||||||
(define (initialize)
|
(define (initialize)
|
||||||
(if (utils:list-file-exists?)
|
(if (file-exists? config:list-file)
|
||||||
(utils:display-hash-ref messages:messages 'file-already-exists)
|
(utils:display-hash-ref messages:messages 'file-already-exists)
|
||||||
(begin
|
(begin
|
||||||
(init-prompt messages:messages 'init-y/n))))
|
(init-prompt messages:messages 'init-y/n))))
|
||||||
|
|
198
messages.rkt
198
messages.rkt
|
@ -4,127 +4,137 @@
|
||||||
|
|
||||||
(provide (all-defined-out))
|
(provide (all-defined-out))
|
||||||
|
|
||||||
|
(define newline "\n")
|
||||||
|
|
||||||
(define messages
|
(define messages
|
||||||
(hash
|
(hash
|
||||||
'show-help (string-append
|
'show-help
|
||||||
"Usage\n"
|
(string-append "\n"
|
||||||
"=====\n"
|
"Conventions used in this help message\n"
|
||||||
(format "If you want to use the ~a or ~a commands, follow the structure below:\n"
|
"====================================="
|
||||||
config:initialize-command
|
"\n\n"
|
||||||
config:list-command)
|
"[command] - [command]s should be replaced by a command from the Command section below without the surrounding \"[\" and \"]\"s."
|
||||||
(format "~a <command>\n\n"
|
"\n\n"
|
||||||
config:program-name)
|
"<argument> - <argument>s should be replaced by user input without the surrounding \"<\" and \">\"s."
|
||||||
|
"\n\n"
|
||||||
|
"Command descriptions\n"
|
||||||
|
"===================="
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
(format "If you want to use the ~a or ~a commands, follow the structure below:\n"
|
;; initialize-command
|
||||||
config:add-command
|
(format "~a" (car config:initialize-command))
|
||||||
config:remove-command)
|
"\n\n"
|
||||||
(format "~a <command> [argument]\n\n" config:program-name)
|
"\t"
|
||||||
|
(format "Creates a list in ~a." config:list-file)
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
"Note: Replace <command> with one of the Commands below without the surrounding \"<\" and \">\".\n\n"
|
;; list-command
|
||||||
|
(format "~a" (car config:list-command))
|
||||||
|
"\n\n"
|
||||||
|
"\t"
|
||||||
|
"Displays items in your list."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
"Commands\n"
|
;; add-command
|
||||||
"========\n"
|
(format "~a" (car config:add-command))
|
||||||
(format "This section describes the commands available for ~a.\n\n" config:program-name)
|
"\n\n"
|
||||||
(format "Note: The commands mentioned in this section should replace the \"<command>\" filler text found in the Usage section above.\n\n")
|
"\t"
|
||||||
|
"Adds an item to your list."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
;; init
|
;; remove-command
|
||||||
(format "~a\n" config:initialize-command)
|
(format "~a" (car config:remove-command))
|
||||||
"====\n"
|
"\n\n"
|
||||||
(format "Creates ~a in ~a. This is where your todo list will be stored.\n\n"
|
"\t"
|
||||||
config:list-file
|
"Removes an item from your list."
|
||||||
config:program-directory)
|
"\n\n"
|
||||||
|
|
||||||
"Example:\n"
|
"Usage examples\n"
|
||||||
(format "~a ~a\n\n" config:program-name config:initialize-command)
|
"=============="
|
||||||
|
"\n\n"
|
||||||
|
;; initialize-command
|
||||||
|
(format "~a" (car config:initialize-command))
|
||||||
|
"\n\n"
|
||||||
|
"\t"
|
||||||
|
(format "~a ~a" config:program-name (car config:initialize-command))
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
;; ls
|
;; list-command
|
||||||
(format "~a\n" config:list-command)
|
(format "~a" (car config:list-command))
|
||||||
"====\n"
|
"\n\n"
|
||||||
"Displays items in your todo list.\n\n"
|
"\t"
|
||||||
|
(format "~a ~a" config:program-name (car config:list-command))
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
"Example:\n"
|
;; add-command
|
||||||
(format "~a ~a\n\n" config:program-name config:list-command)
|
(format "~a" (car config:add-command))
|
||||||
|
"\n\n"
|
||||||
|
"\t"
|
||||||
|
(format "~a ~a this is an item without double quotation marks" config:program-name (car config:add-command))
|
||||||
|
"\n\n"
|
||||||
|
"\t"
|
||||||
|
(format "~a ~a \"this is an item surrounded by double quotation marks\"" config:program-name (car config:add-command))
|
||||||
|
"\n\n"
|
||||||
|
"\t"
|
||||||
|
"Note: Grave accents (`) and single quotation marks (\') cannot be used with this command."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
(format "~a [argument(s)]\n" config:add-command)
|
;; remove-command
|
||||||
"=================\n"
|
(format "~a" (car config:remove-command))
|
||||||
"Adds an item to the list.\n\n"
|
"\n\n"
|
||||||
|
"\t"
|
||||||
|
(format "~a ~a 2" config:program-name (car config:remove-command))
|
||||||
|
"\n\n"
|
||||||
|
"\t"
|
||||||
|
"Note: The example above will remove the third item from your list, because the list starts at zero."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
"Examples:\n"
|
"Can't see the whole help message?\n"
|
||||||
(format "~a ~a this is an unquoted item\n" config:program-name config:add-command)
|
"================================="
|
||||||
(format "~a ~a \"this is a quoted item\"\n\n" config:program-name config:add-command)
|
"\n\n"
|
||||||
|
"\t"
|
||||||
|
(format "Try running \"~a -h | less\" (without the double quotation marks), so you can use the arrow keys to scroll up and down." config:program-name)
|
||||||
|
"\n\n"
|
||||||
|
"\t"
|
||||||
|
"When you want to quit, type \"q\" (without the double quotation marks)."
|
||||||
|
"\n\n")
|
||||||
|
|
||||||
(format "~a [argument]\n" config:remove-command)
|
'empty-list "> There is nothing in your list.\n"
|
||||||
"=============\n"
|
|
||||||
"Removes an item from the list.\n\n"
|
|
||||||
|
|
||||||
"Example:\n"
|
'show-usage (format "> For usage type \"~a -h\" (without the double quotation marks).\n" config:program-name)
|
||||||
(format "~a ~a 1\n\n" config:program-name config:remove-command)
|
|
||||||
|
|
||||||
(format "Note: You may have to run `~a ~a` to see which number corresponds to which item in your todo list."
|
'creating (format "> Creating a list in ~a...\n" config:list-file)
|
||||||
config:program-name
|
|
||||||
config:list-command)
|
|
||||||
" "
|
|
||||||
"In the example above, the first item was removed from the todo list.\n\n"
|
|
||||||
|
|
||||||
"Can't see the whole help message?\n"
|
'creation-error (format "> Error: Could not create a list file in ~a.\n" config:list-file)
|
||||||
"=================================\n"
|
|
||||||
(format "Try running `~a -h | less` so you can use the arrow keys to scroll up and down."
|
|
||||||
config:program-name)
|
|
||||||
" "
|
|
||||||
"When you want to quit, type `q` (without the grave accents).\n")
|
|
||||||
|
|
||||||
'empty-todo-list "> There is nothing in your list.\n"
|
'file-already-exists (format "> Error: A list file already exists in ~a.\n" config:list-file)
|
||||||
|
|
||||||
'show-usage (format "> For usage type `~a -h` or `~a --help`.\n"
|
'successfully-created (format "> Your list file was successfully created in ~a.\n" config:list-file)
|
||||||
config:program-name
|
|
||||||
config:program-name)
|
|
||||||
|
|
||||||
'creating (format "> Creating ~a in ~a.\n"
|
'file-not-found (format "> Error: Could not find ~a.\n" config:list-file)
|
||||||
config:list-file
|
|
||||||
config:program-directory)
|
|
||||||
|
|
||||||
'creation-error (string-append
|
'item-not-found "> Error: Could not find that item.\n"
|
||||||
(format "> Error: Could not create a(n) ~a in ~a.\n"
|
|
||||||
config:list-file
|
|
||||||
config:program-directory)
|
|
||||||
"> This might be due to directory permissions.\n")
|
|
||||||
|
|
||||||
'file-already-exists (format "> Error: ~a already exists in ~a~a.\n"
|
'init-y/n (format (string-append "> A list file will be created in ~a.\n"
|
||||||
config:program-name
|
"> Are you sure you want to continue? [y/n].\n")
|
||||||
config:program-directory
|
config:list-file)
|
||||||
config:list-file)
|
|
||||||
|
|
||||||
'successfully-created (format "> ~a has been successfully created in ~a.\n"
|
'try-init (format "> Try typing \"~a ~a\" to set it up (without the double quotation marks).\n"
|
||||||
config:program-directory
|
config:program-name (car config:initialize-command))
|
||||||
config:list-file)
|
|
||||||
|
|
||||||
'file-not-found (format "> Error: Could not find ~a~a\n"
|
'terminating (format "> Exited ~a.\n" config:program-name)
|
||||||
config:program-directory
|
|
||||||
config:list-file)
|
|
||||||
|
|
||||||
'init-y/n (string-append
|
'choose-y/n "> Error: Please choose y or n\n"
|
||||||
(format "> ~a will be created in ~a.\n"
|
|
||||||
config:list-file
|
|
||||||
config:program-directory)
|
|
||||||
"> Are you sure you want to continue? [y/n]\n")
|
|
||||||
|
|
||||||
'try-init (format "> Try typing `~a ~a` to set it up (without the grave accents).\n"
|
'not-in-list "> Error: Item does not exist\n"
|
||||||
config:program-name
|
|
||||||
config:initialize-command)
|
|
||||||
|
|
||||||
'terminating (format "> Exiting ~a\n" config:program-name)
|
'item-added-prefix "> Added "
|
||||||
|
|
||||||
'choose-y/n "> Error: Please choose y or n\n"
|
'item-added-suffix " to list\n"
|
||||||
|
|
||||||
'not-in-list "> Error: Item does not exist\n"
|
'item-removed-prefix "> Removed "
|
||||||
|
|
||||||
'item-added-prefix "> Added "
|
'item-removed-suffix " from list\n"))
|
||||||
|
|
||||||
'item-added-suffix " to list\n"
|
|
||||||
|
|
||||||
'item-removed-prefix "> Removed "
|
|
||||||
|
|
||||||
'item-removed-suffix " from list\n"))
|
|
||||||
|
|
||||||
(define y/n (hash 'yes '("yes" "Yes" "y" "Y")
|
(define y/n (hash 'yes '("yes" "Yes" "y" "Y")
|
||||||
'no '("no" "No" "n" "N")))
|
'no '("no" "No" "n" "N")))
|
||||||
|
|
2
rodo.rkt
2
rodo.rkt
|
@ -5,4 +5,4 @@
|
||||||
(define (main args)
|
(define (main args)
|
||||||
(args:check-args args))
|
(args:check-args args))
|
||||||
|
|
||||||
(main (current-command-line-arguments))
|
(main (vector->list (current-command-line-arguments)))
|
||||||
|
|
169
utils.rkt
169
utils.rkt
|
@ -1,120 +1,129 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(require (prefix-in file: racket/file)
|
(require (prefix-in file: racket/file)
|
||||||
(prefix-in list: racket/list)
|
(prefix-in list: racket/list)
|
||||||
(prefix-in string: racket/string)
|
(prefix-in string: racket/string)
|
||||||
(prefix-in config: "config.rkt")
|
(prefix-in config: "config.rkt")
|
||||||
(prefix-in messages: "messages.rkt"))
|
(prefix-in messages: "messages.rkt"))
|
||||||
|
|
||||||
(provide (all-defined-out))
|
(provide (all-defined-out))
|
||||||
|
|
||||||
(define (list-file-exists?)
|
(define (create-file-600 a-file)
|
||||||
(file-exists? config:path-to-list-file))
|
(let ([opened-file (open-output-file a-file #:mode 'text #:exists 'truncate)])
|
||||||
|
|
||||||
(define (program-directory-exists?)
|
|
||||||
(directory-exists? config:program-directory))
|
|
||||||
|
|
||||||
(define (create-list-file-600 a-file)
|
|
||||||
(let ([opened-file (open-output-file a-file
|
|
||||||
#:mode 'text
|
|
||||||
#:exists 'truncate)])
|
|
||||||
(close-output-port opened-file))
|
(close-output-port opened-file))
|
||||||
(file-or-directory-permissions a-file #o600))
|
(file-or-directory-permissions a-file #o600))
|
||||||
|
|
||||||
(define (create-program-directory-700 a-directory)
|
(define (create-directory-700 a-directory)
|
||||||
(make-directory a-directory)
|
(make-directory a-directory)
|
||||||
(file-or-directory-permissions a-directory #o700))
|
(file-or-directory-permissions a-directory #o700))
|
||||||
|
|
||||||
(define (display-hash-ref hash-list key)
|
(define (display-hash-ref hash-list key)
|
||||||
(display (hash-ref hash-list key)))
|
(display (hash-ref hash-list key)))
|
||||||
|
|
||||||
(define (file->string-list a-file)
|
(define (list->ascending-numbers lst)
|
||||||
(let ([todo-list (file:file->lines a-file
|
(list:range (length lst)))
|
||||||
#:mode 'text
|
|
||||||
#:line-mode 'any)])
|
|
||||||
todo-list))
|
|
||||||
|
|
||||||
(define (list-file-empty? a-file)
|
(define (list->dotted-ascending-numbers lst)
|
||||||
(list:empty? (file->string-list a-file)))
|
|
||||||
|
|
||||||
(define (get-removed-item lst args)
|
|
||||||
(list-ref (file->string-list lst) (string->number args)))
|
|
||||||
|
|
||||||
(define (surround-with-quotation-marks args)
|
|
||||||
(display (string-append "\"" args "\"")))
|
|
||||||
|
|
||||||
(define (list->list-of-dotted-numbers lst)
|
|
||||||
(map (lambda (x) (string-append x ". "))
|
(map (lambda (x) (string-append x ". "))
|
||||||
(map number->string (list:range (length lst)))))
|
(map number->string (list->ascending-numbers lst))))
|
||||||
|
|
||||||
(define (list->numbered-list lst)
|
(define (list->numbered-list lst)
|
||||||
(map (lambda (x y) (string-append x y))
|
(map (lambda (x y) (string-append x y))
|
||||||
(list->list-of-dotted-numbers lst)
|
(list->dotted-ascending-numbers lst)
|
||||||
lst))
|
lst))
|
||||||
|
|
||||||
(define (file->numbered-list-as-lines a-file)
|
(define (file->vertically-numbered-list a-file)
|
||||||
(string:string-join (list->numbered-list (file->string-list a-file))
|
(string:string-join
|
||||||
"\n"
|
(list->numbered-list (file:file->lines a-file))
|
||||||
#:after-last "\n"))
|
"\n"
|
||||||
|
#:after-last "\n"))
|
||||||
|
|
||||||
(define (append-item-to-list args lst)
|
(define (surround-with-quotation-marks item)
|
||||||
(reverse (cons args (reverse (file->string-list lst)))))
|
(string-append "\"" item "\""))
|
||||||
|
|
||||||
(define (display-item-added args)
|
(define (display-item-added item)
|
||||||
(display-hash-ref messages:messages 'item-added-prefix)
|
(display-hash-ref messages:messages 'item-added-prefix)
|
||||||
(surround-with-quotation-marks args)
|
(display (surround-with-quotation-marks item))
|
||||||
(display-hash-ref messages:messages 'item-added-suffix))
|
(display-hash-ref messages:messages 'item-added-suffix))
|
||||||
|
|
||||||
(define (display-item-removed args)
|
(define (display-item-removed args)
|
||||||
(display-hash-ref messages:messages 'item-removed-prefix)
|
(display-hash-ref messages:messages 'item-removed-prefix)
|
||||||
(surround-with-quotation-marks args)
|
(display (surround-with-quotation-marks args))
|
||||||
(display-hash-ref messages:messages 'item-removed-suffix))
|
(display-hash-ref messages:messages 'item-removed-suffix))
|
||||||
|
|
||||||
|
;; TODO: Turn into a check-show-list-conditions and then break
|
||||||
|
;; the rest down into separate functions
|
||||||
(define (show-list-from-file a-file)
|
(define (show-list-from-file a-file)
|
||||||
(cond [(and (program-directory-exists?)
|
(cond
|
||||||
(list-file-exists?))
|
;; If exists and not empty
|
||||||
(if (list-file-empty? a-file)
|
[(and (file-exists? config:list-file)
|
||||||
(display-hash-ref messages:messages 'empty-todo-list)
|
(not (null? (file:file->lines a-file))))
|
||||||
(display (file->numbered-list-as-lines a-file)))]
|
(display (file->vertically-numbered-list a-file))]
|
||||||
[else
|
|
||||||
(display-hash-ref messages:messages 'file-not-found)
|
|
||||||
(display-hash-ref messages:messages 'try-init)]))
|
|
||||||
|
|
||||||
(define (write-item-to-file a-file args)
|
;; If exists and empty
|
||||||
(let ([new-list (append-item-to-list args a-file)])
|
[(and (file-exists? config:list-file)
|
||||||
(file:display-to-file (string:string-join new-list "\n")
|
(null? (file:file->lines a-file)))
|
||||||
a-file
|
(display-hash-ref messages:messages 'empty-list)]
|
||||||
#:mode 'text
|
|
||||||
#:exists 'truncate))
|
|
||||||
(display-item-added args))
|
|
||||||
|
|
||||||
;; The cdr here prevents user commands, such as "add" being added to the file
|
;; If not exist
|
||||||
|
[(and (not (file-exists? config:list-file)))
|
||||||
|
(begin
|
||||||
|
(display-hash-ref messages:messages 'file-not-found)
|
||||||
|
(display-hash-ref messages:messages 'try-init))]
|
||||||
|
|
||||||
|
;; Otherwise
|
||||||
|
[else (display-hash-ref messages:messages 'show-usage)]))
|
||||||
|
|
||||||
|
;; TODO: Change this to just use append with lst and (list args)
|
||||||
|
(define (append-item-to-list args lst)
|
||||||
|
(reverse (cons args (reverse (file:file->lines lst)))))
|
||||||
|
|
||||||
|
;; TODO: Turn into a check-add-conditions and then break
|
||||||
|
;; the rest down into separate functions
|
||||||
(define (add-item-to-list a-file args)
|
(define (add-item-to-list a-file args)
|
||||||
(if (and (program-directory-exists?)
|
(if (and (file-exists? config:list-file))
|
||||||
(list-file-exists?))
|
(let* ([item (string:string-join (cdr args) " ")]
|
||||||
(write-item-to-file a-file (string:string-join (cdr (vector->list args))))
|
[new-list (append-item-to-list item config:list-file)])
|
||||||
;; Else
|
(file:display-to-file (string:string-join new-list "\n")
|
||||||
|
config:list-file
|
||||||
|
#:mode 'text
|
||||||
|
#:exists 'truncate)
|
||||||
|
(display-item-added item))
|
||||||
(begin
|
(begin
|
||||||
(display-hash-ref messages:messages 'file-not-found)
|
(display-hash-ref messages:messages 'file-not-found)
|
||||||
(display-hash-ref messages:messages 'try-init))))
|
(display-hash-ref messages:messages 'try-init))))
|
||||||
|
|
||||||
(define (remove-item-from-list-file a-file args)
|
;; TODO: Turn into a check-remove-conditions and then break
|
||||||
(let* ([removed-item (get-removed-item a-file args)]
|
;; the rest down into separate functions
|
||||||
[new-list (remove removed-item (file->string-list a-file))])
|
(define (remove-item-from-list args)
|
||||||
(file:display-to-file (string:string-join new-list "\n")
|
(cond
|
||||||
a-file
|
;; If directory and file exist, but file is empty
|
||||||
#:mode 'text
|
[(and (directory-exists? config:program-directory)
|
||||||
#:exists 'truncate)
|
(file-exists? config:list-file)
|
||||||
(display-item-removed removed-item)))
|
(null? config:list-file))
|
||||||
|
(display-hash-ref messages:messages 'empty-list)]
|
||||||
|
|
||||||
(define (remove-item-from-list a-file args)
|
;; If directory and file exist, and file is not empty
|
||||||
(cond [(list-file-empty? a-file)
|
[(and (directory-exists? config:program-directory)
|
||||||
(display-hash-ref messages:messages 'empty-todo-list)]
|
(file-exists? config:list-file)
|
||||||
[(and (program-directory-exists?)
|
(not (null? config:list-file)))
|
||||||
(list-file-exists?))
|
(let ([user-args (string->number (list-ref args 1))]
|
||||||
(remove-item-from-list-file a-file (vector-ref args 1))]
|
;; Length subtract one because the numbering starts at zero
|
||||||
[(and (not (program-directory-exists?))
|
[list-length (sub1 (length (file:file->lines config:list-file)))])
|
||||||
(not (list-file-exists?)))
|
(if (not (> user-args list-length))
|
||||||
(begin
|
(let* ([item-to-remove (list-ref (file:file->lines config:list-file) user-args)]
|
||||||
(display-hash-ref messages:messages 'file-not-found)
|
[new-list (remove item-to-remove (file:file->lines config:list-file))])
|
||||||
(display-hash-ref messages:messages 'try-init))]))
|
(file:display-to-file (string:string-join new-list "\n")
|
||||||
|
config:list-file
|
||||||
|
#:mode 'text
|
||||||
|
#:exists 'truncate)
|
||||||
|
(display-item-removed item-to-remove))
|
||||||
|
;; Else
|
||||||
|
(display-hash-ref messages:messages 'item-not-found)))]
|
||||||
|
|
||||||
|
;; If directory and file don't exist
|
||||||
|
[(and (not (directory-exists? config:program-directory))
|
||||||
|
(not (file-exists? config:list-file)))
|
||||||
|
(begin
|
||||||
|
(display-hash-ref messages:messages 'file-not-found)
|
||||||
|
(display-hash-ref messages:messages 'try-init))]))
|
||||||
|
|
Loading…
Reference in New Issue