Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 24 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,30 @@ LeetCode brings you offer, and now Emacs brings you LeetCode!

1. Execute `leetcode` command, and in problem list buffer:

| Keymap | Description |
|---------------------|------------------------------------------|
| o | show current problem |
| O | show problem by prompting problem id |
| v | view the current problem |
| V | view a problem by prompting problem id |
| b | show the current problem in browser |
| B | show a problem by problem id in browser |
| c | start coding the current problem |
| C | start coding a problem by problem id |
| s | filter problems by regex |
| t | filter problems by tag |
| T | toggle tag display |
| d | filter problems by difficulty |
| r | reset filters |
| P | toggle paid problems display |
| g (z for evil-mode) | refresh without fetching from LeetCode |
| G (Z for evil-mode) | refresh all problems |
| L | change prefer language |
| RET | show current problem |
| TAB | view current problem |
| Keymap | Description |
|---------------------|------------------------------------------ |
| o | show current problem |
| O | show problem by prompting problem id |
| v | view the current problem |
| V | view a problem by prompting problem id |
| b | show the current problem in browser |
| B | show a problem by problem id in browser |
| c | start coding the current problem |
| C | start coding a problem by problem id |
| s | filter problems by regex |
| S | filter problems by status |
| t | filter problems by tag |
| f | reorder problems by id/acceptance%/frequency% |
| F | toggle reverse order |
| T | toggle tag display |
| d | filter problems by difficulty |
| r | reset filters |
| P | toggle paid problems display |
| g (z for evil-mode) | refresh without fetching from LeetCode |
| G (Z for evil-mode) | refresh all problems |
| L | change prefer language |
| RET | show current problem |
| TAB | view current problem |

2. Press `<RET>`, show problem detail, move cursor to "solve it", press `<RET>` again, start coding!

Expand Down
70 changes: 62 additions & 8 deletions leetcode.el
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ For example: :lang 'C++' and :lang-slug 'cpp', :lang 'C#' and
:title String
:title-slug String
:acceptance String
:frequency String
:difficulty String {Easy,Medium,Hard}
:paid-only Boolean {t|nil}
:likes Number
Expand All @@ -178,7 +179,7 @@ For example: :lang 'C++' and :lang-slug 'cpp', :lang 'C#' and

'id' is frontend id in LeetCode. We almost always use frontend id
in 'leetcode.el'."
status id backend-id title title-slug acceptance
status id backend-id title title-slug acceptance frequency
difficulty paid-only likes dislikes tags content
snippets testcases)

Expand Down Expand Up @@ -237,14 +238,20 @@ python3, ruby, rust, scala, swift, mysql, mssql, oraclesql.")
(defconst leetcode--code-end "// code_end"
"Code end mark in LeetCode description.")

(defvar leetcode--filter-status nil "Filter rows by status.")
(defvar leetcode--filter-regex nil "Filter rows by regex.")
(defvar leetcode--filter-tag nil "Filter rows by tag.")
(defvar leetcode--filter-difficulty nil
"Filter rows by difficulty, it can be \"easy\", \"medium\" and \"hard\".")

(defvar leetcode--order "id" "Order of problems, it can be \"id\", \"frequency\" or \"acceptance\".")
(defvar leetcode--reverse-order nil "Reverse order of problems.")

(defconst leetcode--all-difficulties '("Easy" "Medium" "Hard"))
(defconst leetcode--paid "•" "Paid mark.")
(defconst leetcode--checkmark "✓" "Checkmark for accepted problem.")
(defconst leetcode--all-statuses '("-" "✗" "✓") "All statuses.")
(defconst leetcode--all-orders '("id" "frequency" "acceptance") "All orderings.")
(defconst leetcode--buffer-name "*leetcode*")

(defface leetcode-paid-face
Expand Down Expand Up @@ -589,6 +596,7 @@ of QUERY-NAME."
:title .title
:title-slug .titleSlug
:acceptance (format "%.1f%%" .acRate)
:frequency (format "%.1f%%" .freqBar)
:difficulty .difficulty
:paid-only (eq .paidOnly t)
:tags (seq-reduce (lambda (tags tag)
Expand Down Expand Up @@ -757,7 +765,9 @@ Return a list of rows, each row is a vector:
(if (or leetcode--display-paid (not (leetcode-problem-paid-only p)))
(let* ((p-status (if (equal (leetcode-problem-status p) "ac")
(leetcode--add-font-lock leetcode--checkmark 'leetcode-checkmark-face)
" "))
(if (equal (leetcode-problem-status p) "notac")
(leetcode--add-font-lock "✗" 'leetcode-error-face)
"-")))
(p-id (leetcode-problem-id p))
(p-title (concat
(leetcode-problem-title p)
Expand All @@ -766,24 +776,29 @@ Return a list of rows, each row is a vector:
(leetcode--add-font-lock leetcode--paid 'leetcode-paid-face)
" ")))
(p-acceptance (leetcode-problem-acceptance p))
(p-frequency (leetcode-problem-frequency p))
(p-difficulty (leetcode--stringify-difficulty (leetcode-problem-difficulty p)))
(p-tags (if leetcode--display-tags (string-join (leetcode-problem-tags p) ", ") ""))
(single-row (vector p-status p-id p-title p-acceptance p-difficulty p-tags)))
(single-row (vector p-status p-id p-title p-acceptance p-frequency p-difficulty p-tags)))
(setq rows (cons single-row rows)))))))

(defun leetcode--row-tags (row)
"Get tags from ROW."
(aref row 5))
(aref row 6))

(defun leetcode--row-difficulty (row)
"Get difficulty from ROW."
(aref row 4))
(aref row 5))

(defun leetcode--filter (rows)
"Filter ROWS by `leetcode--filter-regex', `leetcode--filter-tag' and `leetcode--filter-difficulty'."
"Filter ROWS by `leetcode--filter-status', `leetcode--filter-regex', `leetcode--filter-tag' and `leetcode--filter-difficulty'."
(seq-filter
(lambda (row)
(and
(if leetcode--filter-status
(let ((status (aref row 0)))
(string= status leetcode--filter-status))
t)
(if leetcode--filter-regex
(let ((title (aref row 2)))
(string-match-p leetcode--filter-regex title))
Expand All @@ -798,6 +813,14 @@ Return a list of rows, each row is a vector:
t)))
rows))

(defun leetcode--sort-by-order (rows)
"Sort ROWS by acceptance."
(let ((num (pcase leetcode--order
("id" 1)
("frequency" 4)
("acceptance" 3)))
(cmp (if leetcode--reverse-order #'> #'<)))
(seq-sort-by (lambda (row) (string-to-number (aref row num))) cmp rows)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; User Command ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Expand All @@ -807,6 +830,21 @@ Return a list of rows, each row is a vector:
(setq leetcode--filter-regex nil)
(setq leetcode--filter-tag nil)
(setq leetcode--filter-difficulty nil)
(setq leetcode--filter-status nil)
(leetcode-refresh))

(defun leetcode-reset-order ()
"Reset order."
(interactive)
(setq leetcode--order "id")
(setq leetcode--reverse-order nil)
(leetcode-refresh))

(defun leetcode-set-filter-status ()
"Set `leetcode--filter-status' from `leetcode--all-statuses' and refresh."
(interactive)
(setq leetcode--filter-status
(completing-read "Status: " leetcode--all-statuses))
(leetcode-refresh))

(defun leetcode-set-filter-regex (regex)
Expand Down Expand Up @@ -836,6 +874,19 @@ Return a list of rows, each row is a vector:
(completing-read "Difficulty: " leetcode--all-difficulties))
(leetcode-refresh))

(defun leetcode-set-order ()
"Set `leetcode--order' from `leetcode--all-orders' and refresh."
(interactive)
(setq leetcode--order
(completing-read "Order by: " leetcode--all-orders))
(leetcode-refresh))

(defun leetcode-toggle-reverse-order ()
"Toggle `leetcode--reverse-order' and refresh."
(interactive)
(setq leetcode--reverse-order (not leetcode--reverse-order))
(leetcode-refresh))

(defun leetcode-toggle-tag-display ()
"Toggle `leetcode--display-tags` and refresh."
(interactive)
Expand Down Expand Up @@ -871,9 +922,9 @@ row."
(defun leetcode-refresh ()
"Make `tabulated-list-entries'."
(interactive)
(let* ((header-names (append '(" " "#" "Problem" "Acceptance" "Difficulty")
(let* ((header-names (append '(" " "#" "Problem" "Acceptance" "Frequency" "Difficulty")
(if leetcode--display-tags '("Tags"))))
(rows (leetcode--filter (leetcode--problems-rows)))
(rows (leetcode--sort-by-order (leetcode--filter (leetcode--problems-rows))))
(headers (leetcode--make-tabulated-headers header-names rows)))
(with-current-buffer (get-buffer-create leetcode--buffer-name)
(leetcode--problems-mode)
Expand Down Expand Up @@ -1442,6 +1493,9 @@ It will restore the layout based on current buffer's name."
(define-key map "c" #'leetcode-solve-current-problem)
(define-key map "C" #'leetcode-solve-problem)
(define-key map "s" #'leetcode-set-filter-regex)
(define-key map "S" #'leetcode-set-filter-status)
(define-key map "f" #'leetcode-set-order)
(define-key map "F" #'leetcode-toggle-reverse-order)
(define-key map "L" #'leetcode-set-prefer-language)
(define-key map "t" #'leetcode-set-filter-tag)
(define-key map "T" #'leetcode-toggle-tag-display)
Expand Down