diff options
Diffstat (limited to 'lisp')
-rw-r--r-- | lisp/mastodon-async.el | 13 | ||||
-rw-r--r-- | lisp/mastodon-discover.el | 2 | ||||
-rw-r--r-- | lisp/mastodon-http.el | 2 | ||||
-rw-r--r-- | lisp/mastodon-inspect.el | 2 | ||||
-rw-r--r-- | lisp/mastodon-iso.el | 370 | ||||
-rw-r--r-- | lisp/mastodon-media.el | 2 | ||||
-rw-r--r-- | lisp/mastodon-notifications.el | 2 | ||||
-rw-r--r-- | lisp/mastodon-profile.el | 59 | ||||
-rw-r--r-- | lisp/mastodon-search.el | 33 | ||||
-rw-r--r-- | lisp/mastodon-tl.el | 290 | ||||
-rw-r--r-- | lisp/mastodon-toot.el | 79 |
11 files changed, 498 insertions, 356 deletions
diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 8a08416..58e7b93 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -229,14 +229,11 @@ ENDPOINT is the endpoint for the stream and timeline." (mastodon-tl--timeline (mastodon-http--get-json (mastodon-http--api endpoint)))) (mastodon-mode) - (setq mastodon-tl--buffer-spec - `(buffer-name - ,buffer-name - endpoint ,endpoint - update-function - ,(if (equal name "notifications") - 'mastodon-notifications--timeline - 'mastodon-tl--timeline))) + (mastodon-tl--set-buffer-spec buffer-name + endpoint + ,(if (equal name "notifications") + 'mastodon-notifications--timeline + 'mastodon-tl--timeline)) (setq-local mastodon-tl--enable-relative-timestamps nil) (setq-local mastodon-tl--display-media-p t) (current-buffer)))) diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 08df46e..1b960e5 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -1,7 +1,9 @@ ;;; mastodon-discover.el --- Use Mastodon.el with discover.el -*- lexical-binding: t -*- ;; Copyright (C) 2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen <johnson.denen@gmail.com> +;; Marty Hiatt <martianhiatus@riseup.net> ;; Maintainer: Marty Hiatt <martianhiatus@riseup.net> ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index d677e57..9ef7aec 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -1,7 +1,9 @@ ;;; mastodon-http.el --- HTTP request/response functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen <johnson.denen@gmail.com> +;; Marty Hiatt <martianhiatus@riseup.net> ;; Maintainer: Marty Hiatt <martianhiatus@riseup.net> ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1") (request "0.3.0")) diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index cbf6a8e..112a753 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -1,7 +1,9 @@ ;;; mastodon-inspect.el --- Client for Mastodon -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen <johnson.denen@gmail.com> +;; Marty Hiatt <martianhiatus@riseup.net> ;; Maintainer: Marty Hiatt <martianhiatus@riseup.net> ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) diff --git a/lisp/mastodon-iso.el b/lisp/mastodon-iso.el index 8baff3c..341593c 100644 --- a/lisp/mastodon-iso.el +++ b/lisp/mastodon-iso.el @@ -33,191 +33,191 @@ ;; https://github.com/Shinmera/language-codes/blob/master/data/iso-639-3.lisp (defvar mastodon-iso-639-1 - '(("ab" "Abkhazian") - ("aa" "Afar") - ("af" "Afrikaans") - ("ak" "Akan") - ("sq" "Albanian") - ("am" "Amharic") - ("ar" "Arabic") - ("an" "Aragonese") - ("hy" "Armenian") - ("as" "Assamese") - ("av" "Avaric") - ("ae" "Avestan") - ("ay" "Aymara") - ("az" "Azerbaijani") - ("bm" "Bambara") - ("ba" "Bashkir") - ("eu" "Basque") - ("be" "Belarusian") - ("bn" "Bengali") - ("bh" "Bihari languages") - ("bi" "Bislama") - ("bs" "Bosnian") - ("br" "Breton") - ("bg" "Bulgarian") - ("my" "Burmese") - ("km" "Central Khmer") - ("ch" "Chamorro") - ("ce" "Chechen") - ("zh" "Chinese") - ("cv" "Chuvash") - ("kw" "Cornish") - ("co" "Corsican") - ("cr" "Cree") - ("hr" "Croatian") - ("cs" "Czech") - ("da" "Danish") - ("dz" "Dzongkha") - ("en" "English") - ("eo" "Esperanto") - ("et" "Estonian") - ("ee" "Ewe") - ("fo" "Faroese") - ("fj" "Fijian") - ("fi" "Finnish") - ("nl" "Dutch" "Flemish") - ("fr" "French") - ("ff" "Fulah") - ("gl" "Galician") - ("lg" "Ganda") - ("ka" "Georgian") - ("de" "German") - ("el" "Greek") - ("gn" "Guarani") - ("gu" "Gujarati") - ("ht" "Haitian" "Haitian Creole") - ("ha" "Hausa") - ("he" "Hebrew") - ("hz" "Herero") - ("hi" "Hindi") - ("ho" "Hiri Motu") - ("hu" "Hungarian") - ("is" "Icelandic") - ("io" "Ido") - ("ig" "Igbo") - ("id" "Indonesian") - ("ia" "Interlingua" "Interlingua (International Auxiliary Language Association)") - ("iu" "Inuktitut") - ("ik" "Inupiaq") - ("ga" "Irish") - ("it" "Italian") - ("ja" "Japanese") - ("jp" "Japanese") - ("jv" "Javanese") - ("kl" "Kalaallisut" "Greenlandic") - ("kn" "Kannada") - ("kr" "Kanuri") - ("ks" "Kashmiri") - ("kk" "Kazakh") - ("ki" "Kikuyu" "Gikuyu") - ("rw" "Kinyarwanda") - ("kv" "Komi") - ("kg" "Kongo") - ("ko" "Korean") - ("ku" "Kurdish") - ("kj" "Kuanyama" "Kwanyama") - ("ky" "Kirghiz" "Kyrgyz") - ("lo" "Lao") - ("la" "Latin") - ("lv" "Latvian") - ("li" "Limburgan" "Limburger" "Limburgish") - ("ln" "Lingala") - ("lt" "Lithuanian") - ("lu" "Luba-Katanga") - ("lb" "Luxembourgish" "Letzeburgesch") - ("mk" "Macedonian") - ("mg" "Malagasy") - ("ms" "Malay") - ("ml" "Malayalam") - ("dv" "Divehi" "Dhivehi" "Maldivian") - ("mt" "Maltese") - ("gv" "Manx") - ("mi" "Maori") - ("mr" "Marathi") - ("mh" "Marshallese") - ("mn" "Mongolian") - ("na" "Nauru") - ("nv" "Navajo" "Navaho") - ("ng" "Ndonga") - ("ne" "Nepali") - ("nd" "Ndebele, North" "North Ndebele") - ("se" "Northern Sami") - ("no" "Norwegian") - ("nb" "Bokmål, Norwegian" "Norwegian Bokmål") - ("ny" "Chichewa" "Chewa" "Nyanja") - ("nn" "Norwegian Nynorsk" "Nynorsk, Norwegian") - ("ie" "Interlingue" "Occidental") - ("oc" "Occitan") - ("oj" "Ojibwa") - ("cu" "Church Slavic" "Old Slavonic" "Church Slavonic" "Old Bulgarian" "Old Church Slavonic") - ("or" "Oriya") - ("om" "Oromo") - ("os" "Ossetian" "Ossetic") - ("pi" "Pali") - ("fa" "Persian") - ("pl" "Polish") - ("pt" "Portuguese") - ("pa" "Panjabi" "Punjabi") - ("ps" "Pushto" "Pashto") - ("qu" "Quechua") - ("ro" "Romanian" "Moldavian" "Moldovan") - ("rm" "Romansh") - ("rn" "Rundi") - ("ru" "Russian") - ("sm" "Samoan") - ("sg" "Sango") - ("sa" "Sanskrit") - ("sc" "Sardinian") - ("gd" "Gaelic" "Scottish Gaelic") - ("sr" "Serbian") - ("sn" "Shona") - ("ii" "Sichuan Yi" "Nuosu") - ("sd" "Sindhi") - ("si" "Sinhala" "Sinhalese") - ("sk" "Slovak") - ("sl" "Slovenian") - ("so" "Somali") - ("st" "Sotho, Southern") - ("nr" "Ndebele, South" "South Ndebele") - ("es" "Spanish" "Castilian") - ("su" "Sundanese") - ("sw" "Swahili") - ("ss" "Swati") - ("sv" "Swedish") - ("tl" "Tagalog") - ("ty" "Tahitian") - ("tg" "Tajik") - ("ta" "Tamil") - ("tt" "Tatar") - ("te" "Telugu") - ("th" "Thai") - ("bo" "Tibetan") - ("ti" "Tigrinya") - ("to" "Tonga (Tonga Islands)") - ("ts" "Tsonga") - ("tn" "Tswana") - ("tr" "Turkish") - ("tk" "Turkmen") - ("tw" "Twi") - ("uk" "Ukrainian") - ("ur" "Urdu") - ("ug" "Uighur" "Uyghur") - ("uz" "Uzbek") - ("ca" "Catalan" "Valencian") - ("ve" "Venda") - ("vi" "Vietnamese") - ("vo" "Volapük") - ("wa" "Walloon") - ("cy" "Welsh") - ("fy" "Western Frisian") - ("wo" "Wolof") - ("xh" "Xhosa") - ("yi" "Yiddish") - ("yo" "Yoruba") - ("za" "Zhuang" "Chuang") - ("zu" "Zulu"))) + '(("Abkhazian" . "ab") + ("Afar" . "aa") + ("Afrikaans" . "af") + ("Akan" . "ak") + ("Albanian" . "sq") + ("Amharic" . "am") + ("Arabic" . "ar") + ("Aragonese" . "an") + ("Armenian" . "hy") + ("Assamese" . "as") + ("Avaric" . "av") + ("Avestan" . "ae") + ("Aymara" . "ay") + ("Azerbaijani" . "az") + ("Bambara" . "bm") + ("Bashkir" . "ba") + ("Basque" . "eu") + ("Belarusian" . "be") + ("Bengali" . "bn") + ("Bihari languages" . "bh") + ("Bislama" . "bi") + ("Bosnian" . "bs") + ("Breton" . "br") + ("Bulgarian" . "bg") + ("Burmese" . "my") + ("Central Khmer" . "km") + ("Chamorro" . "ch") + ("Chechen" . "ce") + ("Chinese" . "zh") + ("Chuvash" . "cv") + ("Cornish" . "kw") + ("Corsican" . "co") + ("Cree" . "cr") + ("Croatian" . "hr") + ("Czech" . "cs") + ("Danish" . "da") + ("Dzongkha" . "dz") + ("English" . "en") + ("Esperanto" . "eo") + ("Estonian" . "et") + ("Ewe" . "ee") + ("Faroese" . "fo") + ("Fijian" . "fj") + ("Finnish" . "fi") + ("Dutch" . "nl") + ("French" . "fr") + ("Fulah" . "ff") + ("Galician" . "gl") + ("Ganda" . "lg") + ("Georgian" . "ka") + ("German" . "de") + ("Greek" . "el") + ("Guarani" . "gn") + ("Gujarati" . "gu") + ("Haitian" . "ht") + ("Hausa" . "ha") + ("Hebrew" . "he") + ("Herero" . "hz") + ("Hindi" . "hi") + ("Hiri Motu" . "ho") + ("Hungarian" . "hu") + ("Icelandic" . "is") + ("Ido" . "io") + ("Igbo" . "ig") + ("Indonesian" . "id") + ("Interlingua" . "ia") + ("Inuktitut" . "iu") + ("Inupiaq" . "ik") + ("Irish" . "ga") + ("Italian" . "it") + ("Japanese" . "ja") + ("Japanese" . "jp") + ("Javanese" . "jv") + ("Kalaallisut" . "kl") + ("Kannada" . "kn") + ("Kanuri" . "kr") + ("Kashmiri" . "ks") + ("Kazakh" . "kk") + ("Kikuyu" . "ki") + ("Kinyarwanda" . "rw") + ("Komi" . "kv") + ("Kongo" . "kg") + ("Korean" . "ko") + ("Kurdish" . "ku") + ("Kuanyama" . "kj") + ("Kirghiz" . "ky") + ("Lao" . "lo") + ("Latin" . "la") + ("Latvian" . "lv") + ("Limburgan" . "li") + ("Lingala" . "ln") + ("Lithuanian" . "lt") + ("Luba-Katanga" . "lu") + ("Luxembourgish" . "lb") + ("Macedonian" . "mk") + ("Malagasy" . "mg") + ("Malay" . "ms") + ("Malayalam" . "ml") + ("Divehi" . "dv") + ("Maltese" . "mt") + ("Manx" . "gv") + ("Maori" . "mi") + ("Marathi" . "mr") + ("Marshallese" . "mh") + ("Mongolian" . "mn") + ("Nauru" . "na") + ("Navajo" . "nv") + ("Ndonga" . "ng") + ("Nepali" . "ne") + ("Ndebele, North" . "nd") + ("Northern Sami" . "se") + ("Norwegian" . "no") + ("Bokmål, Norwegian" . "nb") + ("Chichewa" . "ny") + ("Norwegian Nynorsk" . "nn") + ("Interlingue" . "ie") + ("Occitan" . "oc") + ("Ojibwa" . "oj") + ("Church Slavic" . "cu") + ("Oriya" . "or") + ("Oromo" . "om") + ("Ossetian" . "os") + ("Pali" . "pi") + ("Persian" . "fa") + ("Polish" . "pl") + ("Portuguese" . "pt") + ("Panjabi" . "pa") + ("Pushto" . "ps") + ("Quechua" . "qu") + ("Romanian" . "ro") + ("Romansh" . "rm") + ("Rundi" . "rn") + ("Russian" . "ru") + ("Samoan" . "sm") + ("Sango" . "sg") + ("Sanskrit" . "sa") + ("Sardinian" . "sc") + ("Gaelic" . "gd") + ("Serbian" . "sr") + ("Shona" . "sn") + ("Sichuan Yi" . "ii") + ("Sindhi" . "sd") + ("Sinhala" . "si") + ("Slovak" . "sk") + ("Slovenian" . "sl") + ("Somali" . "so") + ("Sotho, Southern" . "st") + ("Ndebele, South" . "nr") + ("Spanish" . "es") + ("Sundanese" . "su") + ("Swahili" . "sw") + ("Swati" . "ss") + ("Swedish" . "sv") + ("Tagalog" . "tl") + ("Tahitian" . "ty") + ("Tajik" . "tg") + ("Tamil" . "ta") + ("Tatar" . "tt") + ("Telugu" . "te") + ("Thai" . "th") + ("Tibetan" . "bo") + ("Tigrinya" . "ti") + ("Tonga (Tonga Islands)" . "to") + ("Tsonga" . "ts") + ("Tswana" . "tn") + ("Turkish" . "tr") + ("Turkmen" . "tk") + ("Twi" . "tw") + ("Ukrainian" . "uk") + ("Urdu" . "ur") + ("Uighur" . "ug") + ("Uzbek" . "uz") + ("Catalan" . "ca") + ("Venda" . "ve") + ("Vietnamese" . "vi") + ("Volapük" . "vo") + ("Walloon" . "wa") + ("Welsh" . "cy") + ("Western Frisian" . "fy") + ("Wolof" . "wo") + ("Xhosa" . "xh") + ("Yiddish" . "yi") + ("Yoruba" . "yo") + ("Zhuang" . "za") + ("Zulu" . "zu"))) ;; web UI doesn't respect these for now (defvar mastodon-iso-639-regional diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index c783130..4e50dbc 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -1,7 +1,9 @@ ;;; mastodon-media.el --- Functions for inlining Mastodon media -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen <johnson.denen@gmail.com> +;; Marty Hiatt <martianhiatus@riseup.net> ;; Maintainer: Marty Hiatt <martianhiatus@riseup.net> ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index f5ddea3..b7fe038 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -1,7 +1,9 @@ ;;; mastodon-notifications.el --- Notification functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen <johnson.denen@gmail.com> +;; Marty Hiatt <martianhiatus@riseup.net> ;; Maintainer: Marty Hiatt <martianhiatus@riseup.net> ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index d9b45c8..36042e7 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -1,7 +1,9 @@ ;;; mastodon-profile.el --- Functions for inspecting Mastodon profiles -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen <johnson.denen@gmail.com> +;; Marty Hiatt <martianhiatus@riseup.net> ;; Maintainer: Marty Hiatt <martianhiatus@riseup.net> ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) @@ -71,6 +73,10 @@ (autoload 'mastodon-tl--get-endpoint "mastodon-tl.el") (autoload 'mastodon-toot--get-max-toot-chars "mastodon-toot") (autoload 'mastodon-tl--add-account-to-list "mastodon-tl") +(autoload 'mastodon-http--get-response "mastodon-http") +(autoload 'mastodon-tl--get-link-header-from-response "mastodon-tl") +(autoload 'mastodon-tl--set-buffer-spec "mastodon-tl") +(autoload 'mastodon-tl--symbol "mastodon-tl") (defvar mastodon-instance-url) (defvar mastodon-tl--buffer-spec) @@ -186,7 +192,9 @@ NO-REBLOGS means do not display boosts in statuses." (mastodon-profile--make-profile-buffer-for mastodon-profile--account "following" - #'mastodon-profile--add-author-bylines) + #'mastodon-profile--add-author-bylines + nil + :headers) (error "Not in a mastodon profile"))) (defun mastodon-profile--open-followers () @@ -196,7 +204,9 @@ NO-REBLOGS means do not display boosts in statuses." (mastodon-profile--make-profile-buffer-for mastodon-profile--account "followers" - #'mastodon-profile--add-author-bylines) + #'mastodon-profile--add-author-bylines + nil + :headers) (error "Not in a mastodon profile"))) (defun mastodon-profile--view-favourites () @@ -279,7 +289,8 @@ JSON is the data returned by the server." (defun mastodon-profile--update-user-profile-note () "Fetch user's profile note and display for editing." (interactive) - (let* ((url (mastodon-http--api "accounts/verify_credentials")) + (let* ((endpoint "accounts/verify_credentials") + (url (mastodon-http--api endpoint)) (json (mastodon-http--get-json url)) (source (alist-get 'source json)) (note (alist-get 'note source)) @@ -287,6 +298,9 @@ JSON is the data returned by the server." (inhibit-read-only t)) (switch-to-buffer-other-window buffer) (text-mode) + (mastodon-tl--set-buffer-spec (buffer-name buffer) + endpoint + nil) (setq-local header-line-format (propertize "Edit your profile note. C-c C-c to send, C-c C-k to cancel." @@ -489,6 +503,9 @@ This endpoint only holds a few preferences. For others, see (switch-to-buffer-other-window buf) (erase-buffer) (special-mode) + (mastodon-tl--set-buffer-spec (buffer-name buf) + "preferences" + nil) (let ((inhibit-read-only t)) (while response (let ((el (pop response))) @@ -552,16 +569,24 @@ FIELDS means provide a fields vector fetched by other means." (defun mastodon-profile--make-profile-buffer-for (account endpoint-type update-function - &optional no-reblogs) + &optional no-reblogs headers) "Display profile of ACCOUNT, using ENDPOINT-TYPE and UPDATE-FUNCTION. -NO-REBLOGS means do not display boosts in statuses." +NO-REBLOGS means do not display boosts in statuses. +HEADERS means also fetch link headers for pagination." (let* ((id (mastodon-profile--account-field account 'id)) (args (when no-reblogs '(("exclude_reblogs" . "t")))) (url (mastodon-http--api (format "accounts/%s/%s" id endpoint-type))) (acct (mastodon-profile--account-field account 'acct)) (buffer (concat "*mastodon-" acct "-" endpoint-type "*")) + (response (if headers + (mastodon-http--get-response url args) + (mastodon-http--get-json url args))) + (json (if headers (car response) response)) + (endpoint (format "accounts/%s/%s" id endpoint-type)) + (link-header (when headers + (mastodon-tl--get-link-header-from-response + (cdr response)))) (note (mastodon-profile--account-field account 'note)) - (json (mastodon-http--get-json url args)) (locked (mastodon-profile--account-field account 'locked)) (followers-count (mastodon-tl--as-string (mastodon-profile--account-field @@ -585,11 +610,11 @@ NO-REBLOGS means do not display boosts in statuses." (switch-to-buffer buffer) (mastodon-mode) (mastodon-profile-mode) - (setq mastodon-profile--account account - mastodon-tl--buffer-spec - `(buffer-name ,buffer - endpoint ,(format "accounts/%s/%s" id endpoint-type) - update-function ,update-function)) + (setq mastodon-profile--account account) + (mastodon-tl--set-buffer-spec buffer + endpoint + update-function + link-header) (let* ((inhibit-read-only t) (is-statuses (string= endpoint-type "statuses")) (is-followers (string= endpoint-type "followers")) @@ -612,9 +637,7 @@ NO-REBLOGS means do not display boosts in statuses." (propertize (concat "@" acct) 'face 'default) (if (equal locked t) - (if (fontp (char-displayable-p #10r9993)) - " 🔒" - " [locked]") + (concat " " (mastodon-tl--symbol 'locked)) "") "\n ------------\n" ;; profile note: @@ -722,14 +745,6 @@ IMG_TYPE is the JSON key from the account data." (message "Loading your profile...") (mastodon-profile--show-user (mastodon-auth--get-account-name))) -(defun mastodon-profile--view-author-profile () - "View the profile of author of present toot." - (interactive) - (let* ((toot-json (mastodon-tl--property 'toot-json)) - (acct (alist-get 'account toot-json)) - (handle (alist-get 'acct acct))) - (mastodon-profile--show-user handle))) - (defun mastodon-profile--account-field (account field) "Return FIELD from the ACCOUNT. FIELD is used to identify regions under 'account" diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 65c5aba..1aed676 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -40,28 +40,23 @@ (autoload 'mastodon-auth--access-token "mastodon-auth") (autoload 'mastodon-http--get-search-json "mastodon-http") (autoload 'mastodon-http--api "mastodon-http") +(autoload 'mastodon-tl--set-buffer-spec "mastodon-tl") + (defvar mastodon-toot--completion-style-for-mentions) (defvar mastodon-instance-url) (defvar mastodon-tl--link-keymap) (defvar mastodon-http--timeout) (defvar mastodon-toot--enable-completion-for-mentions) -(defvar mastodon-tl--buffer-spec) ;; functions for completion of mentions in mastodon-toot -(defun mastodon-search--get-user-info-@-capf (account) +(defun mastodon-search--get-user-info-@ (account) "Get user handle, display name and account URL from ACCOUNT." (list (concat "@" (cdr (assoc 'acct account))) (cdr (assoc 'url account)) (cdr (assoc 'display_name account)))) -(defun mastodon-search--get-user-info-@ (account) - "Get user handle, display name and account URL from ACCOUNT." - (list (cdr (assoc 'display_name account)) - (concat "@" (cdr (assoc 'acct account))) - (cdr (assoc 'url account)))) - -(defun mastodon-search--search-accounts-query (query &optional capf) +(defun mastodon-search--search-accounts-query (query) "Prompt for a search QUERY and return accounts synchronously. Returns a nested list containing user handle, display name, and URL." (interactive "sSearch mastodon for: ") @@ -69,9 +64,7 @@ Returns a nested list containing user handle, display name, and URL." (response (if (equal mastodon-toot--completion-style-for-mentions "following") (mastodon-http--get-json url `(("q" . ,query) ("following" . "true")) :silent) (mastodon-http--get-json url `(("q" . ,query)) :silent)))) - (if capf - (mapcar #'mastodon-search--get-user-info-@-capf response) - (mapcar #'mastodon-search--get-user-info-@ response)))) + (mapcar #'mastodon-search--get-user-info-@ response))) ;; functions for tags completion: @@ -101,11 +94,9 @@ QUERY is the string to search." (mastodon-mode) (let ((inhibit-read-only t)) (erase-buffer) - (setq mastodon-tl--buffer-spec - `(buffer-name ,buffer - endpoint ,(format "api/v1/trends") - update-function - (lambda (toot) (message "Trends.")))) + (mastodon-tl--set-buffer-spec buffer + "api/v1/trends" + nil) ;; hashtag results: (insert (mastodon-tl--set-face (concat "\n ------------\n" @@ -141,11 +132,9 @@ QUERY is the string to search." (mastodon-mode) (let ((inhibit-read-only t)) (erase-buffer) - (setq mastodon-tl--buffer-spec - `(buffer-name ,buffer - endpoint ,(format "api/v2/search") - update-function - (lambda (toot) (message "Searched.")))) + (mastodon-tl--set-buffer-spec buffer + "api/v2/search" + nil) ;; user results: (insert (mastodon-tl--set-face (concat "\n ------------\n" diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 1a726c4..76cca6c 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1,6 +1,7 @@ ;;; mastodon-tl.el --- HTTP request/response functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen <johnson.denen@gmail.com> ;; Marty Hiatt <martianhiatus@riseup.net> ;; Maintainer: Marty Hiatt <martianhiatus@riseup.net> @@ -36,6 +37,7 @@ (require 'thingatpt) ; for word-at-point (require 'time-date) (require 'cl-lib) +(require 'mastodon-iso) (require 'mpv nil :no-error) @@ -78,6 +80,11 @@ (autoload 'mastodon-http--build-params-string "mastodon-http") (autoload 'mastodon-notifications--filter-types-list "mastodon-notifications") (autoload 'mastodon-toot--get-toot-edits "mastodon-toot") +(autoload 'mastodon-toot--update-status-fields "mastodon-toot") +(autoload 'mastodon-toot--compose-buffer "mastodon-toot") + +(defvar mastodon-toot--visibility) +(defvar mastodon-active-user) (when (require 'mpv nil :no-error) (declare-function mpv-start "mpv")) @@ -122,6 +129,23 @@ nil." :group 'mastodon-tl :type '(boolean :tag "Whether to display user avatars in timelines")) +(defcustom mastodon-tl--symbols + '((reply . ("💬" . "R")) + (boost . ("🔁" . "B")) + (favourite . ("⭐" . "F")) + (bookmark . ("🔖" . "K")) + (media . ("📹" . "[media]")) + (verified . ("" . "V")) + (locked . ("🔒" . "[locked]")) + (private . ("🔒" . "[followers]")) + (direct . ("✉" . "[direct]")) + (edited . ("✍" . "[edited]"))) + "A set of symbols (and fallback strings) to be used in timeline. +If a symbol does not look right (tofu), it means your +font settings do not support it." + :type '(alist :key-type symbol :value-type string) + :group 'mastodon-tl) + (defvar-local mastodon-tl--update-point nil "When updating a mastodon buffer this is where new toots will be inserted. @@ -136,10 +160,6 @@ If nil `(point-min)' is used instead.") (defvar-local mastodon-tl--timestamp-update-timer nil "The timer that, when set will scan the buffer to update the timestamps.") -(defvar mastodon-tl--link-header-buffers - '("*mastodon-favourites*" "*mastodon-bookmarks*") - "A list of buffers that use link headers for pagination.") - ;; KEYMAPS (defvar mastodon-tl--link-keymap @@ -241,11 +261,21 @@ types of mastodon links and not just shr.el-generated ones.") (when (require 'mpv nil :no-error) (let ((map (make-sparse-keymap))) (define-key map (kbd "<C-return>") 'mastodon-tl--mpv-play-video-from-byline) - (define-key map (kbd "<return>") 'mastodon-profile--view-author-profile) + (define-key map (kbd "<return>") 'mastodon-profile--get-toot-author) (keymap-canonicalize map))) "The keymap to be set for the author byline. It is active where point is placed by `mastodon-tl--goto-next-toot.'") +(defun mastodon-tl--symbol (name) + "Return the unicode symbol (as a string) corresponding to NAME. +If symbol is not displayable, an ASCII equivalent is returned. If +NAME is not part of the symbol table, '?' is returned." + (if-let* ((symbol (alist-get name mastodon-tl--symbols))) + (if (char-displayable-p (string-to-char (car symbol))) + (car symbol) + (cdr symbol)) + "?")) + ;; NAV (defun mastodon-tl--next-tab-item () @@ -622,13 +652,13 @@ this just means displaying toot client." ;; the toot having just been favourited/boosted. (concat (when boosted (mastodon-tl--format-faved-or-boosted-byline - (mastodon-tl--return-boost-char))) + (mastodon-tl--symbol 'boost))) (when faved (mastodon-tl--format-faved-or-boosted-byline - (mastodon-tl--return-fave-char))) + (mastodon-tl--symbol 'favourite))) (when bookmarked (mastodon-tl--format-faved-or-boosted-byline - (mastodon-tl--return-bookmark-char)))) + (mastodon-tl--symbol 'bookmark)))) ;; we remove avatars from the byline also, so that they also do not mess ;; with `mastodon-tl--goto-next-toot': (when (and mastodon-tl--show-avatars @@ -644,14 +674,9 @@ this just means displaying toot client." (funcall author-byline toot) ;; visibility: (cond ((equal visibility "direct") - (if (fontp (char-displayable-p #10r9993)) - " ✉" - " [direct]")) + (concat " " (mastodon-tl--symbol 'direct))) ((equal visibility "private") - (if (fontp (char-displayable-p #10r128274)) - " 🔒" - " [followers]"))) - ;; action: + (concat " " (mastodon-tl--symbol 'private)))) (funcall action-byline toot) " " ;; TODO: Once we have a view for toot (responses etc.) make @@ -679,9 +704,9 @@ this just means displaying toot client." 'keymap mastodon-tl--shr-map-replacement))))) (if edited-time (concat - (if (fontp (char-displayable-p #10r128274)) - " ✍ " - " [edited] ") + " " + (mastodon-tl--symbol 'edited) + " " (propertize (format-time-string mastodon-toot-timestamp-format edited-parsed) @@ -700,30 +725,6 @@ this just means displaying toot client." (mastodon-toot--get-toot-edits (alist-get 'id toot))) 'byline t)))) -(defun mastodon-tl--return-boost-char () - "" - (cond - ((fontp (char-displayable-p #10r128257)) - "🔁") - (t - "B"))) - -(defun mastodon-tl--return-fave-char () - "" - (cond - ((fontp (char-displayable-p #10r11088)) - "⭐") - ((fontp (char-displayable-p #10r9733)) - "★") - (t - "F"))) - -(defun mastodon-tl--return-bookmark-char () - "" - (if (fontp (char-displayable-p #10r128278)) - "🔖" - "K")) - (defun mastodon-tl--format-edit-timestamp (timestamp) "Convert edit TIMESTAMP into a descriptive string." (let ((parsed (ts-human-duration @@ -1162,7 +1163,7 @@ this just means displaying toot client." (let* ((poll (mastodon-tl--field 'poll toot)) (expiry (mastodon-tl--field 'expires_at poll)) (expired-p (if (eq (mastodon-tl--field 'expired poll) :json-false) nil t)) - (multi (mastodon-tl--field 'multiple poll)) + ;; (multi (mastodon-tl--field 'multiple poll)) (voters-count (mastodon-tl--field 'voters_count poll)) (vote-count (mastodon-tl--field 'votes_count poll)) (options (mastodon-tl--field 'options poll)) @@ -1374,10 +1375,12 @@ BUFFER is buffer name, ENDPOINT is buffer's enpoint, UPDATE-FUNCTION is its update function. LINK-HEADER is the http Link header if present." (setq mastodon-tl--buffer-spec - `(buffer-name ,buffer - endpoint ,endpoint - update-function ,update-function - link-header ,link-header))) + `(account ,(cons mastodon-active-user + mastodon-instance-url) + buffer-name ,buffer + endpoint ,endpoint + update-function ,update-function + link-header ,link-header))) (defun mastodon-tl--more-json (endpoint id) "Return JSON for timeline ENDPOINT before ID." @@ -1457,7 +1460,7 @@ ID is that of the toot to view." (mastodon-mode) (mastodon-tl--set-buffer-spec buffer (format "statuses/%s" id) - (lambda (_toot) (message "END of thread."))) + nil) (let ((inhibit-read-only t)) (mastodon-tl--toot toot :detailed-p)))))) @@ -1472,7 +1475,8 @@ ID is that of the toot to view." (if (or (string= type "follow_request") (string= type "follow")) ; no can thread these (error "No thread") - (let* ((url (mastodon-http--api (format "statuses/%s/context" id))) + (let* ((endpoint (format "statuses/%s/context" id)) + (url (mastodon-http--api endpoint)) (buffer (format "*mastodon-thread-%s*" id)) (toot ;; refetch current toot in case we just faved/boosted: @@ -1494,10 +1498,9 @@ ID is that of the toot to view." (with-output-to-temp-buffer buffer (switch-to-buffer buffer) (mastodon-mode) - (mastodon-tl--set-buffer-spec - buffer - (format "statuses/%s/context" id) - (lambda (_toot) (message "END of thread."))) + (mastodon-tl--set-buffer-spec buffer + endpoint + nil) (let ((inhibit-read-only t)) (mastodon-tl--timeline (alist-get 'ancestors context)) (goto-char (point-max)) @@ -1511,6 +1514,65 @@ ID is that of the toot to view." ;; else just print the lone toot: (mastodon-tl--single-toot id))))))) + +(defun mastodon-tl--mute-thread () + "Mute the thread displayed in the current buffer. +Note that you can only (un)mute threads you have posted in." + (interactive) + (mastodon-tl--mute-or-unmute-thread)) + +(defun mastodon-tl--unmute-thread () + "Mute the thread displayed in the current buffer. +Note that you can only (un)mute threads you have posted in." + (interactive) + (mastodon-tl--mute-or-unmute-thread :unmute)) + +(defun mastodon-tl--mute-or-unmute-thread (&optional unmute) + "Mute a thread. +If UNMUTE, unmute it." + (let ((endpoint (mastodon-tl--get-endpoint))) + (if (string-suffix-p "context" endpoint) ; thread view + (let* ((id + (save-match-data + (string-match "statuses/\\(?2:[[:digit:]]+\\)/context" + endpoint) + (match-string 2 endpoint))) + (we-posted-p (mastodon-tl--user-in-thread-p id)) + (url (mastodon-http--api + (if unmute + (format "statuses/%s/unmute" id) + (format "statuses/%s/mute" id))))) + (if (not we-posted-p) + (message "You can only (un)mute a thread you have posted in.") + (when (if unmute + (y-or-n-p "Unnute this thread? ") + (y-or-n-p "Mute this thread? ")) + (let ((response (mastodon-http--post url))) + (mastodon-http--triage response + (lambda () + (if unmute + (message "Thread unmuted!") + (message "Thread muted!"))))))))))) + +(defun mastodon-tl--user-in-thread-p (id) + "Return non-nil if the logged-in user has posted to the current thread. +ID is that of the post the context is currently displayed for." + (let* ((context-json (mastodon-http--get-json + (mastodon-http--api (format "statuses/%s/context" id)) + nil :silent)) + (ancestors (alist-get 'ancestors context-json)) + (descendants (alist-get 'descendants context-json)) + (a-ids (mapcar (lambda (status) + (alist-get 'id + (alist-get 'account status))) + ancestors)) + (d-ids (mapcar (lambda (status) + (alist-get 'id + (alist-get 'account status))) + descendants))) + (or (member (mastodon-auth--get-account-id) a-ids) + (member (mastodon-auth--get-account-id) d-ids)))) + ;;; LISTS (defun mastodon-tl--get-users-lists () @@ -1957,6 +2019,9 @@ INSTANCE is an instance domain name." (let ((buf (get-buffer-create "*mastodon-instance*"))) (with-current-buffer buf (switch-to-buffer-other-window buf) + (mastodon-tl--set-buffer-spec (buffer-name buf) + "instance" + nil) (let ((inhibit-read-only t)) (erase-buffer) (special-mode) @@ -2079,16 +2144,18 @@ IND is the optional indentation level to print at." ;;; FOLLOW/BLOCK/MUTE, ETC -(defun mastodon-tl--follow-user (user-handle &optional notify) +(defun mastodon-tl--follow-user (user-handle &optional notify langs) "Query for USER-HANDLE from current status and follow that user. If NOTIFY is \"true\", enable notifications when that user posts. If NOTIFY is \"false\", disable notifications when that user posts. -Can be called to toggle NOTIFY on users already being followed." +Can be called to toggle NOTIFY on users already being followed. +LANGS is an array parameters alist of languages to filer user's posts by." (interactive (list (mastodon-tl--interactive-user-handles-get "follow"))) (mastodon-tl--do-if-toot - (mastodon-tl--do-user-action-and-response user-handle "follow" nil notify))) + (mastodon-tl--do-user-action-and-response + user-handle "follow" nil notify langs))) (defun mastodon-tl--enable-notify-user-posts (user-handle) "Query for USER-HANDLE and enable notifications when they post." @@ -2105,6 +2172,33 @@ Can be called to toggle NOTIFY on users already being followed." (mastodon-tl--interactive-user-handles-get "disable"))) (mastodon-tl--follow-user user-handle "false")) +(defun mastodon-tl--filter-user-user-posts-by-language (user-handle) + "Query for USER-HANDLE and enable notifications when they post. +This feature is experimental and for now not easily varified by +the instance API." + (interactive + (list + (mastodon-tl--interactive-user-handles-get "filter by language"))) + (let ((langs (mastodon-tl--read-filter-langs))) + (mastodon-tl--do-if-toot + (mastodon-tl--follow-user user-handle nil langs)))) + +(defun mastodon-tl--read-filter-langs (&optional langs) + "Read language choices and return an alist array parameter. +LANGS is the accumulated array param alist if we re-run recursively." + (let* ((langs-alist langs) + (choice (completing-read "Filter user's posts by language: " + mastodon-iso-639-1))) + (when choice + (setq langs-alist + (push `("languages[]" . ,(alist-get choice mastodon-iso-639-1 + nil nil + #'string=)) + langs-alist)) + (if (y-or-n-p "Filter by another language? ") + (mastodon-tl--read-filter-langs langs-alist) + langs-alist)))) + (defun mastodon-tl--unfollow-user (user-handle) "Query for USER-HANDLE from current status and unfollow that user." (interactive @@ -2147,6 +2241,16 @@ Can be called to toggle NOTIFY on users already being followed." (message "Looks like you have no mutes to unmute!") (mastodon-tl--do-user-action-and-response user-handle "unmute" t))) +(defun mastodon-tl--dm-user (user-handle) + "Query for USER-HANDLE from current status and compose a message to that user." + (interactive + (list + (mastodon-tl--interactive-user-handles-get "message"))) + (mastodon-tl--do-if-toot + (mastodon-toot--compose-buffer (concat "@" user-handle)) + (setq mastodon-toot--visibility "direct") + (mastodon-toot--update-status-fields))) + (defun mastodon-tl--interactive-user-handles-get (action) "Get the list of user-handles for ACTION from the current toot." (mastodon-tl--do-if-toot @@ -2197,12 +2301,13 @@ Action must be either \"unblock\" or \"unmute\"." nil ; predicate t)))) -(defun mastodon-tl--do-user-action-and-response (user-handle action &optional negp notify) +(defun mastodon-tl--do-user-action-and-response (user-handle action &optional negp notify langs) "Do ACTION on user USER-HANDLE. NEGP is whether the action involves un-doing something. If NOTIFY is \"true\", enable notifications when that user posts. If NOTIFY is \"false\", disable notifications when that user posts. -NOTIFY is only non-nil when called by `mastodon-tl--follow-user'." +NOTIFY is only non-nil when called by `mastodon-tl--follow-user'. +LANGS is an array parameters alist of languages to filer user's posts by." (let* ((account (if negp ;; if unmuting/unblocking, we got handle from mute/block list (mastodon-profile--search-account-by-handle @@ -2218,35 +2323,41 @@ NOTIFY is only non-nil when called by `mastodon-tl--follow-user'." (name (if (not (string-empty-p (mastodon-profile--account-field account 'display_name))) (mastodon-profile--account-field account 'display_name) (mastodon-profile--account-field account 'username))) - (url (mastodon-http--api - (if notify - (format "accounts/%s/%s?notify=%s" user-id action notify) - (format "accounts/%s/%s" user-id action))))) + (args (cond (notify + `(("notify" . ,notify))) + (langs langs) + (t nil))) + (url (mastodon-http--api (format "accounts/%s/%s" user-id action)))) (if account (if (equal action "follow") ; y-or-n for all but follow - (mastodon-tl--do-user-action-function url name user-handle action notify) + (mastodon-tl--do-user-action-function url name user-handle action notify args) (when (y-or-n-p (format "%s user %s? " action name)) - (mastodon-tl--do-user-action-function url name user-handle action))) + (mastodon-tl--do-user-action-function url name user-handle action args))) (message "Cannot find a user with handle %S" user-handle)))) -(defun mastodon-tl--do-user-action-function (url name user-handle action &optional notify) +(defun mastodon-tl--do-user-action-function (url name user-handle action &optional notify args) "Post ACTION on user NAME/USER-HANDLE to URL. NOTIFY is either \"true\" or \"false\", and used when we have been called -by `mastodon-tl--follow-user' to enable or disable notifications." - (let ((response (mastodon-http--post url))) - (mastodon-http--triage response - (lambda () - (cond ((string-equal notify "true") - (message "Receiving notifications for user %s (@%s)!" - name user-handle)) - ((string-equal notify "false") - (message "Not receiving notifications for user %s (@%s)!" - name user-handle)) - ((or (string-equal action "mute") - (string-equal action "unmute")) - (message "User %s (@%s) %sd!" name user-handle action)) - ((eq notify nil) - (message "User %s (@%s) %sed!" name user-handle action))))))) +by `mastodon-tl--follow-user' to enable or disable notifications. +ARGS is an alist of any parameters to send with the request." + (let ((response (mastodon-http--post url args))) + (mastodon-http--triage + response + (lambda () + (cond ((string-equal notify "true") + (message "Receiving notifications for user %s (@%s)!" + name user-handle)) + ((string-equal notify "false") + (message "Not receiving notifications for user %s (@%s)!" + name user-handle)) + ((or (string-equal action "mute") + (string-equal action "unmute")) + (message "User %s (@%s) %sd!" name user-handle action)) + ((assoc "languages[]" args #'equal) + (message "User %s filtered by language(s): %s" name + (mapconcat #'cdr args " "))) + ((eq notify nil) + (message "User %s (@%s) %sed!" name user-handle action))))))) ;; FOLLOW TAGS @@ -2327,11 +2438,22 @@ For use after e.g. deleting a toot." (param (cadr split))) (concat url-base "&" param))) +(defun mastodon-tl--use-link-header-p () + "Return t if we are in a view that uses Link header pagination. +Currently this includes favourites, bookmarks, and profile pages +when showing followers or accounts followed." + (let ((buf (buffer-name (current-buffer))) + (endpoint (mastodon-tl--get-endpoint))) + (or (member buf '("*mastodon-favourites*" "*mastodon-bookmarks*")) + (and (string-prefix-p "accounts" endpoint) + (or (string-suffix-p "followers" endpoint) + (string-suffix-p "following" endpoint)))))) + (defun mastodon-tl--more () "Append older toots to timeline, asynchronously." (interactive) (message "Loading older toots...") - (if (member (buffer-name (current-buffer)) mastodon-tl--link-header-buffers) + (if (mastodon-tl--use-link-header-p) ;; link-header: can't build a URL with --more-json-async, endpoint/id: (let* ((next (car (mastodon-tl--link-header))) ;;(prev (cadr (mastodon-tl--link-header))) @@ -2532,7 +2654,7 @@ from the start if it is nil." "Initialize BUFFER-NAME with timeline targeted by ENDPOINT asynchronously. UPDATE-FUNCTION is used to recieve more toots. HEADERS means to also collect the response headers. Used for paginating -favourites." +favourites and bookmarks." (let ((url (mastodon-http--api endpoint)) (buffer (concat "*mastodon-" buffer-name "*"))) (if headers @@ -2545,8 +2667,8 @@ favourites." "Initialize BUFFER with timeline targeted by ENDPOINT. UPDATE-FUNCTION is used to recieve more toots. RESPONSE is the data returned from the server by -`mastodon-http--process-json', a cons cell of JSON and http -headers." +`mastodon-http--process-json', with arg HEADERS a cons cell of +JSON and http headers, without it just the JSON." (let* ((json (if headers (car response) response)) (headers (if headers (cdr response) nil)) (link-header (mastodon-tl--get-link-header-from-response headers))) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 59a3813..121a590 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -1,6 +1,7 @@ ;;; mastodon-toot.el --- Minor mode for sending Mastodon toots -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen <johnson.denen@gmail.com> ;; Marty Hiatt <martianhiatus@riseup.net> ;; Maintainer: Marty Hiatt <martianhiatus@riseup.net> @@ -78,7 +79,7 @@ (autoload 'mastodon-http--build-array-params-alist "mastodon-http") (autoload 'mastodon-tl--get-endpoint "mastodon-tl") (autoload 'mastodon-http--put "mastodon-http") -(autoload 'mastodon-tl--return-fave-char "mastodon-tl") +(autoload 'mastodon-tl--symbol "mastodon-tl") ;; for mastodon-toot--translate-toot-text (autoload 'mastodon-tl--content "mastodon-tl") @@ -345,8 +346,8 @@ TYPE is a symbol, either 'favourite or 'boost." (list 'favourited-p (not faved)))) (mastodon-toot--action-success (if boost-p - (mastodon-tl--return-boost-char) - (mastodon-tl--return-fave-char)) + (mastodon-tl--symbol 'boost) + (mastodon-tl--symbol 'favourite)) byline-region remove)) (message (format "%s #%s" (if boost-p msg action) id)))))) (message (format "Nothing to %s here?!?" action-string))))) @@ -366,23 +367,21 @@ TYPE is a symbol, either 'favourite or 'boost." "Bookmark or unbookmark toot at point." (interactive) (let* ( ;(toot (mastodon-tl--property 'toot-json)) - (id (mastodon-tl--property 'base-toot-id)) - ;; (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (bookmarked-p (mastodon-tl--property 'bookmarked-p)) - (prompt (if bookmarked-p - (format "Toot already bookmarked. Remove? ") - (format "Bookmark this toot? "))) - (byline-region - (when id - (mastodon-tl--find-property-range 'byline (point)))) - (action (if bookmarked-p "unbookmark" "bookmark")) - (bookmark-str (if (fontp (char-displayable-p #10r128278)) - "🔖" - "K")) - (message (if bookmarked-p - "Bookmark removed!" - "Toot bookmarked!")) - (remove (when bookmarked-p t))) + (id (mastodon-tl--property 'base-toot-id)) + ;; (mastodon-tl--as-string (mastodon-tl--toot-id toot))) + (bookmarked-p (mastodon-tl--property 'bookmarked-p)) + (prompt (if bookmarked-p + (format "Toot already bookmarked. Remove? ") + (format "Bookmark this toot? "))) + (byline-region + (when id + (mastodon-tl--find-property-range 'byline (point)))) + (action (if bookmarked-p "unbookmark" "bookmark")) + (bookmark-str (mastodon-tl--symbol 'bookmark)) + (message (if bookmarked-p + "Bookmark removed!" + "Toot bookmarked!")) + (remove (when bookmarked-p t))) (if byline-region (when (y-or-n-p prompt) (mastodon-toot--action @@ -790,8 +789,8 @@ instance to edit a toot." (defun mastodon-toot--insert-toot-iter (it) "Insert iteration IT of toot." - (let ((content (alist-get 'content it)) - (account (alist-get 'account it))) + (let ((content (alist-get 'content it))) + ;; (account (alist-get 'account it)) ;; TODO: handle polls, media (mastodon-tl--render-text content))) @@ -829,7 +828,7 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." ""))) (defun mastodon-toot--get-bounds (regex) - "Get bounds of tag or handle before point." + "Get bounds of tag or handle before point using REGEX." ;; needed because # and @ are not part of any existing thing at point (save-match-data (save-excursion @@ -855,8 +854,7 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." ;; just for the annotation-function? (setq mastodon-toot-completions (mastodon-search--search-accounts-query - (buffer-substring-no-properties start end) - :capf)))) + (buffer-substring-no-properties start end))))) :exclusive 'no :annotation-function (lambda (candidate) @@ -1115,16 +1113,14 @@ LENGTH is the maximum character length allowed for a poll option." ("30 days" . ,(number-to-string (* 60 60 24 30))))) (defun mastodon-toot--set-toot-lang () - "Prompt for a language and return its two letter ISO 639 1 code." + "Prompt for a language and set `mastodon-toot--language'. +Return its two letter ISO 639 1 code." (interactive) - (let* ((langs (mapcar (lambda (x) - (cons (cadr x) - (car x))) - mastodon-iso-639-1)) - (choice (completing-read "Language for this toot: " - langs))) + (let* ((choice (completing-read "Language for this toot: " + mastodon-iso-639-1))) (setq mastodon-toot--language - (alist-get choice langs nil nil 'equal)))) + (alist-get choice mastodon-iso-639-1 nil nil 'equal)) + (message "Language set to %s" choice))) ;; we'll need to revisit this if the binds get ;; more diverse than two-chord bindings @@ -1216,6 +1212,9 @@ REPLY-TEXT is the text of the toot being replied to." (propertize "Visibility" 'toot-post-visibility t) " ⋅ " + (propertize "Language" + 'toot-post-language t) + " " (propertize "CW" 'toot-post-cw-flag t) " " @@ -1269,6 +1268,8 @@ REPLY-JSON is the full JSON of the toot being replied to." (point-min))) (cw-region (mastodon-tl--find-property-range 'toot-post-cw-flag (point-min))) + (lang-region (mastodon-tl--find-property-range 'toot-post-language + (point-min))) (toot-string (buffer-substring-no-properties (cdr header-region) (point-max)))) (add-text-properties (car count-region) (cdr count-region) @@ -1284,10 +1285,16 @@ REPLY-JSON is the full JSON of the toot being replied to." "private") "followers-only" mastodon-toot--visibility)))) + (add-text-properties (car lang-region) (cdr lang-region) + (list 'display + (if mastodon-toot--language + (format "Language: %s" + mastodon-toot--language) + ""))) (add-text-properties (car nsfw-region) (cdr nsfw-region) (list 'display (if mastodon-toot--content-nsfw (if mastodon-toot--media-attachments - "NSFW" "NSFW (no effect until attachments added)") + "NSFW" "NSFW (for attachments only)") "") 'face 'mastodon-cw-face)) (add-text-properties (car cw-region) (cdr cw-region) @@ -1439,7 +1446,9 @@ a draft into the buffer." 'completion-at-point-functions #'mastodon-toot--tags-capf) ;; company - (when mastodon-toot--use-company-for-completion + (when (and mastodon-toot--use-company-for-completion + (require 'company nil :no-error)) + (declare-function 'company-mode-on "company") (set (make-local-variable 'company-backends) (add-to-list 'company-backends 'company-capf)) (company-mode-on))) |