From ee112a9c7161d4befdda5c7f55f3fa018c7d5805 Mon Sep 17 00:00:00 2001 From: m455 Date: Fri, 15 Nov 2019 07:37:40 -0500 Subject: [PATCH 1/2] made a new branch for rewriting rodo --- args.rkt | 27 ++++---- config.rkt | 6 +- init.rkt | 10 +-- messages.rkt | 4 +- rodo.rkt | 2 +- utils.rkt | 169 +++++++++++++++++++++++++++------------------------ 6 files changed, 114 insertions(+), 104 deletions(-) diff --git a/args.rkt b/args.rkt index ebbae0f..b164409 100644 --- a/args.rkt +++ b/args.rkt @@ -2,45 +2,44 @@ (require (prefix-in config: "config.rkt") (prefix-in init: "init.rkt") + (prefix-in file: racket/file) (prefix-in messages: "messages.rkt") (prefix-in utils: "utils.rkt")) (provide (all-defined-out)) (define (check-args args) - (let ([args-length (vector-length args)]) + (let ([args-length (length args)]) (cond [(equal? args-length 0) (utils:display-hash-ref messages:messages 'show-usage)] ;; help [(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)] ;; init [(and (equal? args-length 1) - (member (vector-ref args 0) config:initialize-command)) + (member (list-ref args 0) config:initialize-command)) (init:initialize)] ;; add [(and (or (equal? args-length 2) (>= args-length 2)) - (member (vector-ref args 0) config:add-command)) - (utils:add-item-to-list config:path-to-list-file args)] + (member (list-ref args 0) config:add-command)) + (utils:add-item-to-list config:list-file args)] ;; ls [(and (equal? args-length 1) - (member (vector-ref args 0) config:list-command)) - (utils:show-list-from-file config:path-to-list-file)] + (member (list-ref args 0) config:list-command)) + (utils:show-list-from-file config:list-file)] ;; rm [(and (equal? args-length 2) - (member (vector-ref args 0) config:remove-command) - (real? (string->number (vector-ref args 1))) - (or (positive? (string->number (vector-ref args 1))) - (zero? (string->number (vector-ref args 1)))) - ;; Length subtract one because the numbering starts at zero - (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)] + (member (list-ref args 0) config:remove-command) + (real? (string->number (list-ref args 1))) + (or (positive? (string->number (list-ref args 1))) + (zero? (string->number (list-ref args 1))))) + (utils:remove-item-from-list args)] [else (utils:display-hash-ref messages:messages 'show-usage)]))) diff --git a/config.rkt b/config.rkt index 284166a..0c433c3 100644 --- a/config.rkt +++ b/config.rkt @@ -1,7 +1,7 @@ #lang racket/base (provide (all-defined-out)) -(define list-file "todo.txt") +(define file-name "todo.txt") (define program-name "rodo") (define program-directory @@ -9,8 +9,8 @@ (expand-user-path (string-append "~/." program-name "/")))) -(define path-to-list-file - (string-append program-directory list-file)) +(define list-file + (string-append program-directory file-name)) (define help-command '("-h" "--help" diff --git a/init.rkt b/init.rkt index 5fd562f..f71acef 100644 --- a/init.rkt +++ b/init.rkt @@ -13,10 +13,10 @@ (cond [(member user-input (hash-ref messages:y/n 'yes)) (begin (utils:display-hash-ref messages:messages 'creating) - (utils:create-program-directory-700 config:program-directory) - (utils:create-list-file-600 config:path-to-list-file) - (if (and (utils:program-directory-exists?) - (utils:list-file-exists?)) + (utils:create-directory-700 config:program-directory) + (utils:create-file-600 config:list-file) + (if (and (directory-exists? config:program-directory) + (file-exists? config:list-file)) (utils:display-hash-ref messages:messages 'successfully-created) (utils:display-hash-ref messages:messages 'creation-error)))] [(member user-input (hash-ref messages:y/n 'no)) @@ -25,7 +25,7 @@ (init-prompt messages:messages 'choose-y/n)]))) (define (initialize) - (if (utils:list-file-exists?) + (if (file-exists? config:list-file) (utils:display-hash-ref messages:messages 'file-already-exists) (begin (init-prompt messages:messages 'init-y/n)))) diff --git a/messages.rkt b/messages.rkt index 244dd9e..defc1fc 100644 --- a/messages.rkt +++ b/messages.rkt @@ -102,6 +102,8 @@ config:program-directory config:list-file) + 'item-not-found "> Error: Could not find that item\n" + 'init-y/n (string-append (format "> ~a will be created in ~a.\n" config:list-file @@ -110,7 +112,7 @@ 'try-init (format "> Try typing `~a ~a` to set it up (without the grave accents).\n" config:program-name - config:initialize-command) + (car config:initialize-command)) 'terminating (format "> Exiting ~a\n" config:program-name) diff --git a/rodo.rkt b/rodo.rkt index 878d44b..7c7ab1a 100644 --- a/rodo.rkt +++ b/rodo.rkt @@ -5,4 +5,4 @@ (define (main args) (args:check-args args)) -(main (current-command-line-arguments)) +(main (vector->list (current-command-line-arguments))) diff --git a/utils.rkt b/utils.rkt index 43e4225..5787ce8 100644 --- a/utils.rkt +++ b/utils.rkt @@ -1,120 +1,129 @@ #lang racket/base -(require (prefix-in file: racket/file) - (prefix-in list: racket/list) - (prefix-in string: racket/string) - (prefix-in config: "config.rkt") +(require (prefix-in file: racket/file) + (prefix-in list: racket/list) + (prefix-in string: racket/string) + (prefix-in config: "config.rkt") (prefix-in messages: "messages.rkt")) (provide (all-defined-out)) -(define (list-file-exists?) - (file-exists? config:path-to-list-file)) - -(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)]) +(define (create-file-600 a-file) + (let ([opened-file (open-output-file a-file #:mode 'text #:exists 'truncate)]) (close-output-port opened-file)) (file-or-directory-permissions a-file #o600)) -(define (create-program-directory-700 a-directory) +(define (create-directory-700 a-directory) (make-directory a-directory) (file-or-directory-permissions a-directory #o700)) (define (display-hash-ref hash-list key) (display (hash-ref hash-list key))) -(define (file->string-list a-file) - (let ([todo-list (file:file->lines a-file - #:mode 'text - #:line-mode 'any)]) - todo-list)) +(define (list->ascending-numbers lst) + (list:range (length lst))) -(define (list-file-empty? a-file) - (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) +(define (list->dotted-ascending-numbers lst) (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) (map (lambda (x y) (string-append x y)) - (list->list-of-dotted-numbers lst) + (list->dotted-ascending-numbers lst) lst)) -(define (file->numbered-list-as-lines a-file) - (string:string-join (list->numbered-list (file->string-list a-file)) - "\n" - #:after-last "\n")) +(define (file->vertically-numbered-list a-file) + (string:string-join + (list->numbered-list (file:file->lines a-file)) + "\n" + #:after-last "\n")) -(define (append-item-to-list args lst) - (reverse (cons args (reverse (file->string-list lst))))) +(define (surround-with-quotation-marks item) + (string-append "\"" item "\"")) -(define (display-item-added args) +(define (display-item-added item) (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)) (define (display-item-removed args) (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)) +;; TODO: Turn into a check-show-list-conditions and then break +;; the rest down into separate functions (define (show-list-from-file a-file) - (cond [(and (program-directory-exists?) - (list-file-exists?)) - (if (list-file-empty? a-file) - (display-hash-ref messages:messages 'empty-todo-list) - (display (file->numbered-list-as-lines a-file)))] - [else - (display-hash-ref messages:messages 'file-not-found) - (display-hash-ref messages:messages 'try-init)])) + (cond + ;; If exists and not empty + [(and (file-exists? config:list-file) + (not (null? (file:file->lines a-file)))) + (display (file->vertically-numbered-list a-file))] -(define (write-item-to-file a-file args) - (let ([new-list (append-item-to-list args a-file)]) - (file:display-to-file (string:string-join new-list "\n") - a-file - #:mode 'text - #:exists 'truncate)) - (display-item-added args)) + ;; If exists and empty + [(and (file-exists? config:list-file) + (null? (file:file->lines a-file))) + (display-hash-ref messages:messages 'empty-todo-list)] -;; 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) - (if (and (program-directory-exists?) - (list-file-exists?)) - (write-item-to-file a-file (string:string-join (cdr (vector->list args)))) - ;; Else + (if (and (file-exists? config:list-file)) + (let* ([item (string:string-join (cdr args) " ")] + [new-list (append-item-to-list item config:list-file)]) + (file:display-to-file (string:string-join new-list "\n") + config:list-file + #:mode 'text + #:exists 'truncate) + (display-item-added item)) (begin (display-hash-ref messages:messages 'file-not-found) (display-hash-ref messages:messages 'try-init)))) -(define (remove-item-from-list-file a-file args) - (let* ([removed-item (get-removed-item a-file args)] - [new-list (remove removed-item (file->string-list a-file))]) - (file:display-to-file (string:string-join new-list "\n") - a-file - #:mode 'text - #:exists 'truncate) - (display-item-removed removed-item))) +;; TODO: Turn into a check-remove-conditions and then break +;; the rest down into separate functions +(define (remove-item-from-list args) + (cond + ;; If directory and file exist, but file is empty + [(and (directory-exists? config:program-directory) + (file-exists? config:list-file) + (null? config:list-file)) + (display-hash-ref messages:messages 'empty-todo-list)] -(define (remove-item-from-list a-file args) - (cond [(list-file-empty? a-file) - (display-hash-ref messages:messages 'empty-todo-list)] - [(and (program-directory-exists?) - (list-file-exists?)) - (remove-item-from-list-file a-file (vector-ref args 1))] - [(and (not (program-directory-exists?)) - (not (list-file-exists?))) - (begin - (display-hash-ref messages:messages 'file-not-found) - (display-hash-ref messages:messages 'try-init))])) + ;; If directory and file exist, and file is not empty + [(and (directory-exists? config:program-directory) + (file-exists? config:list-file) + (not (null? config:list-file))) + (let ([user-args (string->number (list-ref args 1))] + ;; Length subtract one because the numbering starts at zero + [list-length (sub1 (length (file:file->lines config:list-file)))]) + (if (not (> user-args list-length)) + (let* ([item-to-remove (list-ref (file:file->lines config:list-file) user-args)] + [new-list (remove item-to-remove (file:file->lines config:list-file))]) + (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))])) From 55638206885f49a8130ee1148b29b8b4a72ecf45 Mon Sep 17 00:00:00 2001 From: m455 Date: Tue, 19 Nov 2019 21:50:28 -0500 Subject: [PATCH 2/2] this push will break everything because I'm rewriting a lot of stuff --- README.md | 18 ++--- args.rkt | 10 +-- config.rkt | 7 +- messages.rkt | 200 ++++++++++++++++++++++++++------------------------- utils.rkt | 4 +- 5 files changed, 126 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index 32c6aa1..3ad0632 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 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 @@ -54,17 +54,17 @@ If you are using a single-file executable, create a wrapper as follows: # Introduction 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 -command line and want a minimal todo list application. +list manager. It is intended for people who spend a lot of their time on the +command line and want a minimal list manager. # Conventions used in this readme -* Notes - Notes signify additional information -* Tips - Tips signify an alternate procedure for completing a step -* Cautions - Cautions signify that damage may occur -* Examples - Examples provide a visual reference of how a procedure would be carried out in the real world +* **Note** - Notes signify additional information +* **Tip**- Tips signify an alternate procedure for completing a step +* **Caution** - Cautions signify that damage may occur +* **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 -* ```Code blocks``` - Code blocks signify file contents +* ```Code block``` - Code blocks signify file contents # 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 -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. diff --git a/args.rkt b/args.rkt index b164409..44a134e 100644 --- a/args.rkt +++ b/args.rkt @@ -14,27 +14,27 @@ [(equal? args-length 0) (utils:display-hash-ref messages:messages 'show-usage)] - ;; help + ;; help-command [(and (equal? args-length 1) (member (list-ref args 0) config:help-command)) (utils:display-hash-ref messages:messages 'show-help)] - ;; init + ;; initialize-command [(and (equal? args-length 1) (member (list-ref args 0) config:initialize-command)) (init:initialize)] - ;; add + ;; add-command [(and (or (equal? args-length 2) (>= args-length 2)) (member (list-ref args 0) config:add-command)) (utils:add-item-to-list config:list-file args)] - ;; ls + ;; list-command [(and (equal? args-length 1) (member (list-ref args 0) config:list-command)) (utils:show-list-from-file config:list-file)] - ;; rm + ;; remove-command [(and (equal? args-length 2) (member (list-ref args 0) config:remove-command) (real? (string->number (list-ref args 1))) diff --git a/config.rkt b/config.rkt index 0c433c3..b19ab37 100644 --- a/config.rkt +++ b/config.rkt @@ -1,7 +1,7 @@ #lang racket/base (provide (all-defined-out)) -(define file-name "todo.txt") +(define file-name "list.txt") (define program-name "rodo") (define program-directory @@ -12,22 +12,27 @@ (define list-file (string-append program-directory file-name)) +;; TODO: pluralize this value's name (define help-command '("-h" "--help" "h" "help")) +;; TODO: pluralize this value's name (define initialize-command '("init" "create" "start" "begin")) +;; TODO: pluralize this value's name (define add-command '("add" "a")) +;; TODO: pluralize this value's name (define list-command '("ls" "list")) +;; TODO: pluralize this value's name (define remove-command '("rm" "remove" "del" diff --git a/messages.rkt b/messages.rkt index defc1fc..2a0f484 100644 --- a/messages.rkt +++ b/messages.rkt @@ -4,129 +4,137 @@ (provide (all-defined-out)) +(define newline "\n") + (define messages (hash - 'show-help (string-append - "Usage\n" - "=====\n" - (format "If you want to use the ~a or ~a commands, follow the structure below:\n" - config:initialize-command - config:list-command) - (format "~a \n\n" - config:program-name) + 'show-help + (string-append "\n" + "Conventions used in this help message\n" + "=====================================" + "\n\n" + "[command] - [command]s should be replaced by a command from the Command section below without the surrounding \"[\" and \"]\"s." + "\n\n" + " - 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" - config:add-command - config:remove-command) - (format "~a [argument]\n\n" config:program-name) + ;; initialize-command + (format "~a" (car config:initialize-command)) + "\n\n" + "\t" + (format "Creates a list in ~a." config:list-file) + "\n\n" - "Note: Replace 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" - "========\n" - (format "This section describes the commands available for ~a.\n\n" config:program-name) - (format "Note: The commands mentioned in this section should replace the \"\" filler text found in the Usage section above.\n\n") + ;; add-command + (format "~a" (car config:add-command)) + "\n\n" + "\t" + "Adds an item to your list." + "\n\n" - ;; init - (format "~a\n" config:initialize-command) - "====\n" - (format "Creates ~a in ~a. This is where your todo list will be stored.\n\n" - config:list-file - config:program-directory) + ;; remove-command + (format "~a" (car config:remove-command)) + "\n\n" + "\t" + "Removes an item from your list." + "\n\n" - "Example:\n" - (format "~a ~a\n\n" config:program-name config:initialize-command) + "Usage examples\n" + "==============" + "\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 - (format "~a\n" config:list-command) - "====\n" - "Displays items in your todo list.\n\n" + ;; list-command + (format "~a" (car config:list-command)) + "\n\n" + "\t" + (format "~a ~a" config:program-name (car config:list-command)) + "\n\n" - "Example:\n" - (format "~a ~a\n\n" config:program-name config:list-command) + ;; add-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) - "=================\n" - "Adds an item to the list.\n\n" + ;; remove-command + (format "~a" (car config:remove-command)) + "\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" - (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) + "Can't see the whole help message?\n" + "=================================" + "\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) - "=============\n" - "Removes an item from the list.\n\n" + 'empty-list "> There is nothing in your list.\n" - "Example:\n" - (format "~a ~a 1\n\n" config:program-name config:remove-command) + 'show-usage (format "> For usage type \"~a -h\" (without the double quotation marks).\n" config:program-name) - (format "Note: You may have to run `~a ~a` to see which number corresponds to which item in your todo list." - config:program-name - config:list-command) - " " - "In the example above, the first item was removed from the todo list.\n\n" + 'creating (format "> Creating a list in ~a...\n" config:list-file) - "Can't see the whole help message?\n" - "=================================\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") + 'creation-error (format "> Error: Could not create a list file in ~a.\n" config:list-file) - '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" - config:program-name - config:program-name) + 'successfully-created (format "> Your list file was successfully created in ~a.\n" config:list-file) - 'creating (format "> Creating ~a in ~a.\n" - config:list-file - config:program-directory) + 'file-not-found (format "> Error: Could not find ~a.\n" config:list-file) - 'creation-error (string-append - (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") + 'item-not-found "> Error: Could not find that item.\n" - 'file-already-exists (format "> Error: ~a already exists in ~a~a.\n" - config:program-name - config:program-directory - config:list-file) + 'init-y/n (format (string-append "> A list file will be created in ~a.\n" + "> Are you sure you want to continue? [y/n].\n") + config:list-file) - 'successfully-created (format "> ~a has been successfully created in ~a.\n" - config:program-directory - config:list-file) + 'try-init (format "> Try typing \"~a ~a\" to set it up (without the double quotation marks).\n" + config:program-name (car config:initialize-command)) - 'file-not-found (format "> Error: Could not find ~a~a\n" - config:program-directory - config:list-file) + 'terminating (format "> Exited ~a.\n" config:program-name) - 'item-not-found "> Error: Could not find that item\n" + 'choose-y/n "> Error: Please choose y or n\n" - 'init-y/n (string-append - (format "> ~a will be created in ~a.\n" - config:list-file - config:program-directory) - "> Are you sure you want to continue? [y/n]\n") + 'not-in-list "> Error: Item does not exist\n" - 'try-init (format "> Try typing `~a ~a` to set it up (without the grave accents).\n" - config:program-name - (car config:initialize-command)) + 'item-added-prefix "> Added " - 'terminating (format "> Exiting ~a\n" config:program-name) + 'item-added-suffix " to list\n" - 'choose-y/n "> Error: Please choose y or n\n" + 'item-removed-prefix "> Removed " - 'not-in-list "> Error: Item does not exist\n" - - 'item-added-prefix "> Added " - - 'item-added-suffix " to list\n" - - 'item-removed-prefix "> Removed " - - 'item-removed-suffix " from list\n")) + 'item-removed-suffix " from list\n")) (define y/n (hash 'yes '("yes" "Yes" "y" "Y") - 'no '("no" "No" "n" "N"))) + 'no '("no" "No" "n" "N"))) diff --git a/utils.rkt b/utils.rkt index 5787ce8..261de65 100644 --- a/utils.rkt +++ b/utils.rkt @@ -63,7 +63,7 @@ ;; If exists and empty [(and (file-exists? config:list-file) (null? (file:file->lines a-file))) - (display-hash-ref messages:messages 'empty-todo-list)] + (display-hash-ref messages:messages 'empty-list)] ;; If not exist [(and (not (file-exists? config:list-file))) @@ -101,7 +101,7 @@ [(and (directory-exists? config:program-directory) (file-exists? config:list-file) (null? config:list-file)) - (display-hash-ref messages:messages 'empty-todo-list)] + (display-hash-ref messages:messages 'empty-list)] ;; If directory and file exist, and file is not empty [(and (directory-exists? config:program-directory)