From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Pranshu Sharma Newsgroups: gmane.emacs.devel Subject: Re: New package: haskell-ts-mode Date: Thu, 29 Aug 2024 20:57:29 +1000 Message-ID: References: <874j74u15e.fsf@posteo.net> <87a5gvsnnn.fsf@posteo.net> <87y14fr5e5.fsf@posteo.net> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="000000000000e108cd0620d0575c" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="22072"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel@gnu.org To: Philip Kaludercic Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Thu Aug 29 13:18:12 2024 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1sjdAJ-0005by-T0 for ged-emacs-devel@m.gmane-mx.org; Thu, 29 Aug 2024 13:18:12 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sjd9R-0000UE-Jd; Thu, 29 Aug 2024 07:17:17 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sjcqf-00005e-98 for emacs-devel@gnu.org; Thu, 29 Aug 2024 06:57:53 -0400 Original-Received: from mail-ot1-x332.google.com ([2607:f8b0:4864:20::332]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sjcqT-0006fA-MB for emacs-devel@gnu.org; Thu, 29 Aug 2024 06:57:53 -0400 Original-Received: by mail-ot1-x332.google.com with SMTP id 46e09a7af769-7092dd03223so167193a34.1 for ; Thu, 29 Aug 2024 03:57:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1724929060; x=1725533860; darn=gnu.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=HwrXSo2kpE7Wz85BecFC+kPm5nKpkaKD0wjXczqbzIM=; b=TxkQd5aAEw3hXMOS0iEzAQBmFUc2UOYBqJcF8YIh9wsAqpcxcJJES6f25vWQLAf0P6 FSTcwWBnr7YCM8csVxA+cjgw9uvxGY9mH/lbPjS2+q4OlGT3wQzOLlaETeTlpT/MLOre 8vdfvvAkV85/bEpup9PFqohTO4yizkPTMT2pac7ukzMklvyPi3OXCEuEfGVcbklUfG9W 47NYonqNf7REx9GPxc0DRRUqNMk82sUeUe1iEgLfLWdFrNR9a9cBkS6fkRN6RW1fsnVZ T0+IKsWLNm/Q2jZLFr4lH7aFpthC13/H/NdjkLmVEZxfNdkwk1l8cHqxdStSbUEcWXIf Jvvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724929060; x=1725533860; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=HwrXSo2kpE7Wz85BecFC+kPm5nKpkaKD0wjXczqbzIM=; b=Za06XDztXSbU21+dVCV2PV70uAe6sEC1fkDELM4XhTHHeT5xMucEKBeSfid8Xyi6Vu +MrIhC+dbeUThZTvURdYeCuon77h8vAmScVkfJZQ/ZhXbY+uYt8vX9sTt3XQwmPEGc3Q 0qXZee0zoIQmEYzIlk/uICW8aOXrcN2rp2ewyUmRaL3NPZxScdgtQJbdhMxLr7Ntw7oZ WQLVwhDt0bpQpn8HUsKE7K3UIXZvwXmI7T5ZE52qUGwuD8Yh8L+NHIX27hlRpKZIEOcS +tP2CV+v9gfEfrHzw6uCr+JNU2WQjpeYF4rU+OkZonMTKR+JrQReMUqNIFlXFG/VeBmW 1NZA== X-Gm-Message-State: AOJu0YxfpERHZ5L7CKyB/cH5WY8WMDlCSZJeXqMq7hDhEazTwgfo0iHU zo0vWch7GgR1Ryfvf5PBOy580jLXJlKpO6hZpJznEDftVcKuM8R4Pn+jFmZJLwfg1Yfjz0+KiRo QBAhy0iZT4i3mzWfCXTC0pzi5unDAFMvo X-Google-Smtp-Source: AGHT+IFYFwJ4IZwPcgvZhjlaOo6cFyFWTUFPI0e30eGe/Gxuy8U2g8oD5ybd64JmuVKNS7WqCDBQ0esPTKO+tSxpkJ4= X-Received: by 2002:a05:6358:524b:b0:1b3:93b7:5945 with SMTP id e5c5f4694b2df-1b603c02c9amr285404255d.2.1724929059914; Thu, 29 Aug 2024 03:57:39 -0700 (PDT) In-Reply-To: <87y14fr5e5.fsf@posteo.net> Received-SPF: pass client-ip=2607:f8b0:4864:20::332; envelope-from=sirsharmapranshu@gmail.com; helo=mail-ot1-x332.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 29 Aug 2024 07:17:16 -0400 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:323178 Archived-At: --000000000000e108cd0620d0575c Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Oh well, haskell-tng-mode is gpl, and I wouldn't consider the contributions 'significant', but I think adding package to NonGNU elpa would be best to avoid drama. One day we might find the mythical prof that teaches his students elisp, till then stay optimistic. btw, I had to pull back your suggested changes to the run haskell function, they did not work On Thu, Aug 29, 2024 at 8:27=E2=80=AFPM Philip Kaludercic wrote: > Pranshu Sharma writes: > > > Oh yeah, I just realised that and fixed the electric pair mode error. > > 1+ > > > The seq-do part I did not code myself, I copied it from haskell-tng-mod= e, > > as stated in the comment. > > That reminds me, haskell-tng-mode is on NonGNU ELPA, but your patch > appears to be for GNU ELPA. If you code is based on haskell-tng-mode, > then there might be licensing issues. Should we add the package to > NonGNU ELPA instead, or can you attest to having no significant > contributions from anyone else? > > > Homework? students? do you teach your students elisp? > > Ugh, no sorry for the misunderstanding. I was a TA for systems > programming and taught C. My point was that LLMs tended to generate > unusual C code. I just have weird sensibilities since then. > > > On Thu, Aug 29, 2024 at 7:07=E2=80=AFPM Philip Kaludercic > > wrote: > > > >> Pranshu Sharma writes: > >> > >> > Hello Phlip, > >> > > >> > Thanks for the edits, I applied all of it apart from when when you > want > >> > defun changed to macro, that does not work, as closures are not > properly > >> > supported by treesit. > >> > >> OK, sorry about the last suggestion then, as I said, I am not familiar > >> with treesitter. > >> > >> > With the spacing, I did what you suggested then used emacs to indent > the > >> > whole page, and added elpaignore file > >> > >> 1+ > >> > >> Note that `electric-pair-pairs' is now malconstructed. It is a list o= f > >> lists, where each list begins with the symbol `cons'. Not a list of > >> cons-cells holding two characters. > >> > >> > Also no, I did not use Ai, what made you think so? > >> > >> There were a some unusual constructs repeated a number of times that I > >> have never seen before (the way you used seq-do was the main example). > >> It reminded me of homework submissions I have seen students submit tha= t > >> /were/ AI generated. > >> > >> > > >> > On Thu, Aug 29, 2024 at 1:18=E2=80=AFAM Philip Kaludercic > > >> > wrote: > >> > > >> >> Pranshu Sharma writes: > >> >> > >> >> > Hello all > >> >> > > >> >> > haskell-ts-mode is a major mode for haskell that uses treesitter = to > >> >> provide > >> >> > features such as indentation and colouring. The mode can be found > at > >> >> > pranshu/haskell-ts-mode: > >> >> > A haskelll mode that uses treesitter - Codeberg.org > >> >> > . > >> >> > >> >> First of all, the spacing and indentation is inconsistent. Please > >> >> address that, and perhaps add a directory local option to enforce > >> >> indentation with spaces to ensure a consistent look. > >> >> > >> >> I cannot comment on the tree-sitter stuff since I don't really > >> >> understand it, but otherwise I have a few comments that I would lik= e > you > >> >> to consider: > >> >> > >> >> diff --git a/haskell-ts-mode.el b/haskell-ts-mode.el > >> >> index 4ba7f42..391db66 100644 > >> >> --- a/haskell-ts-mode.el > >> >> +++ b/haskell-ts-mode.el > >> >> @@ -2,7 +2,6 @@ > >> >> > >> >> ;; Copyright (C) 2024 Pranshu Sharma > >> >> > >> >> - > >> >> ;; Author: Pranshu Sharma > >> >> ;; URL: https://codeberg.org/pranshu/haskell-ts-mode > >> >> ;; Package-Requires: ((emacs "29.3")) > >> >> @@ -23,6 +22,7 @@ > >> >> ;; along with this program. If not, see < > >> https://www.gnu.org/licenses/>. > >> >> > >> >> ;;; Commentary: > >> >> + > >> >> ;; This is a WIP mode that uses treesitter to provide all the basi= c > >> >> ;; major mode stuff, like indentation, font lock, etc... > >> >> > >> >> @@ -31,6 +31,7 @@ > >> >> (require 'comint) > >> >> (require 'treesit) > >> >> > >> >> +;; From what I understand this is necessary for tree-sitter modes, > but > >> >> can you at least also add the ARGLIST argument. Also, some functio= ns > >> such > >> >> as `treesit-induce-sparse-tree' appear not to be used? > >> >> (declare-function treesit-parser-create "treesit.c") > >> >> (declare-function treesit-induce-sparse-tree "treesit.c") > >> >> (declare-function treesit-node-child "treesit.c") > >> >> @@ -46,10 +47,11 @@ > >> >> (otherwise signature))) > >> >> > >> >> (defvar haskell-ts-use-indent t > >> >> - "Set to nil if you don't want to use Emacs indent.") > >> >> + "Set to nil if you don't want to use Emacs indent.") ;rephrase > this > >> >> would the double negation > >> >> > >> >> (defvar haskell-ts-font-lock-level 4 > >> >> "Level of font lock, 1 for minimum highlghting and 4 for > maximum.") > >> >> +;; both of these variables are actually user options and should be > >> >> declared using `'defcustom'! > >> >> > >> >> (defvar haskell-ts-prettify-symbols-alits > >> >> '(("\\" . "=CE=BB") > >> >> @@ -60,6 +62,7 @@ > >> >> ("<=3D" . "=E2=89=A5") > >> >> (">=3D" . "=E2=89=A4"))) > >> >> > >> >> +;; Checkdoc complains that > >> >> (defun haskell-ts-font-lock () > >> >> (treesit-font-lock-rules > >> >> :language 'haskell > >> >> @@ -157,7 +160,7 @@ > >> >> ((parent-is "apply") parent -1) > >> >> ((node-is "quasiquote") grand-parent 2) > >> >> ((parent-is "quasiquote_body") (lambda (_ _ c) c) 0) > >> >> - ;; Do Hg > >> >> + ;; Do Hg ;; what does "Hg" mean? > >> >> ((lambda (node parent bol) > >> >> (let ((n (treesit-node-prev-sibling node))) > >> >> (while (string=3D "comment" (treesit-node-type n)) > >> >> @@ -232,6 +235,7 @@ > >> >> > >> >> ;; Copied from haskell-tng-mode, changed a bit > >> >> (defvar haskell-ts-mode-syntax-table > >> >> + ;; Should this be wrapped in an `eval-when-compile'? > >> >> (let ((table (make-syntax-table))) > >> >> (map-char-table > >> >> (lambda (k v) > >> >> @@ -241,7 +245,7 @@ > >> >> (modify-syntax-entry k "_" table)))) > >> >> (char-table-parent table)) > >> >> ;; whitechar > >> >> - (seq-do > >> >> + (seq-do ;seq-do has a relatively hi= gh > >> >> overhead, try to avoid it > >> >> (lambda (it) (modify-syntax-entry it " " table)) > >> >> (string-to-list "\r\n\f\v \t")) > >> >> ;; ascSymbol > >> >> @@ -268,46 +272,40 @@ > >> >> (modify-syntax-entry ?\{ "(}1nb" table) > >> >> (modify-syntax-entry ?\} "){4nb" table) > >> >> (modify-syntax-entry ?- "_ 123" table) ;; TODO --> is not = a > >> >> comment > >> >> - (seq-do > >> >> - (lambda (it) (modify-syntax-entry it ">" table)) > >> >> - (string-to-list "\r\n\f\v")) > >> >> + (dolist (c (string-to-list "\r\n\f\v")) ;though unrolling > >> wouldn't > >> >> be bad either > >> >> + (modify-syntax-entry c ">" table)) > >> >> + > >> >> table)) > >> >> > >> >> +(defun haskell-ts-imenu-name-function (check-func) > >> >> + (lambda (node) > >> >> + (if (funcall check-func node) > >> >> + (haskell-ts-defun-name node) > >> >> + nil))) > >> >> > >> >> -(defmacro haskell-ts-imenu-name-function (check-func) > >> >> - `(lambda (node) > >> >> - (if (funcall ,check-func node) > >> >> - (haskell-ts-defun-name node) > >> >> - nil))) > >> >> - > >> >> -(defun haskell-ts-indent-para() > >> >> +(defun haskell-ts-indent-para () > >> >> "Indent the current paragraph." > >> >> (interactive) > >> >> - (save-excursion > >> >> - (backward-paragraph) > >> >> - (let ((p (point))) > >> >> - (forward-paragraph) > >> >> - (indent-region p (point))))) > >> >> + (when-let ((par (bounds-of-thing-at-point 'paragraph))) > >> >> + (indent-region (car par) (cdr par)))) > >> >> > >> >> (defvar haskell-ts-mode-map > >> >> (let ((km (make-sparse-keymap))) > >> >> (define-key km (kbd "C-c C-c") > 'haskell-ts-compile-region-and-go) > >> >> (define-key km (kbd "C-c C-r") 'haskell-ts-run-haskell) > >> >> - (define-key km (kbd "C-M-q") 'haskell-ts-indent-para) > >> >> + (define-key km (kbd "C-M-q") 'haskell-ts-indent-para) ;is this > >> >> necessary when `prog-fill-reindent-defun' is bound to M-q? > >> >> km) > >> >> - "Map for haskell-ts-mode") > >> >> + "Map for haskell-ts-mode.") > >> >> > >> >> ;;;###autoload > >> >> (define-derived-mode haskell-ts-mode prog-mode "haskell ts mode" > >> >> "Major mode for Haskell files using tree-sitter." > >> >> - :syntax-table haskell-ts-mode-syntax-table > >> >> - :interactive t > >> >> (unless (treesit-ready-p 'haskell) > >> >> (error "Tree-sitter for Haskell is not available")) > >> >> (treesit-parser-create 'haskell) > >> >> (setq-local treesit-defun-type-regexp > >> >> "\\(?:\\(?:function\\|struct\\)_definition\\)") > >> >> ;; Indent > >> >> - (and haskell-ts-use-indent > >> >> + (and haskell-ts-use-indent ;do you mean `when'? > >> >> (setq-local treesit-simple-indent-rules > haskell-ts-indent-rules) > >> >> (setq-local indent-tabs-mode nil)) > >> >> ;; Comment > >> >> @@ -316,21 +314,21 @@ > >> >> (setq-local comment-start-skip "\\(?: \\|^\\)-+") > >> >> ;; Elecric > >> >> (setq-local electric-pair-pairs > >> >> - (list (cons ?` ?`) (cons ?\( ?\)) (cons ?{ ?}) (cons > ?\" > >> >> ?\") (cons ?\[ ?\]))) > >> >> + '((?` . ?`) (?\( . ?\)) (?{ . ?}) (?\" . ?\") (?\[ . > >> ?\]))) > >> >> ;; Nav > >> >> - (setq-local treesit-defun-name-function 'haskell-ts-defun-name) > >> >> + (setq-local treesit-defun-name-function #'haskell-ts-defun-name) > >> >> (setq-local treesit-defun-type-regexp "function") > >> >> (setq-local prettify-symbols-alist > haskell-ts-prettify-symbols-alits) > >> >> ;; Imenu > >> >> (setq-local treesit-simple-imenu-settings > >> >> `((nil haskell-ts-imenu-func-node-p nil > >> >> - ,(haskell-ts-imenu-name-function > >> >> 'haskell-ts-imenu-func-node-p)) > >> >> + ,(haskell-ts-imenu-name-function > >> >> #'haskell-ts-imenu-func-node-p)) > >> >> ("Signatures.." haskell-ts-imenu-sig-node-p nil > >> >> - ,(haskell-ts-imenu-name-function > >> >> 'haskell-ts-imenu-sig-node-p)) > >> >> + ,(haskell-ts-imenu-name-function > >> >> #'haskell-ts-imenu-sig-node-p)) > >> >> ("Data..." haskell-ts-imenu-data-type-p nil > >> >> (lambda (node) > >> >> (treesit-node-text (treesit-node-child node > 1)))))) > >> >> - ;; font-lock. > >> >> + ;; font-lock > >> >> (setq-local treesit-font-lock-level haskell-ts-font-lock-level) > >> >> (setq-local treesit-font-lock-settings (haskell-ts-font-lock)) > >> >> (setq-local treesit-font-lock-feature-list > >> >> @@ -379,23 +377,32 @@ > >> >> > >> >> (defun haskell-ts-run-haskell() > >> >> (interactive) > >> >> - (when (not (comint-check-proc "*haskell*")) > >> >> - (set-buffer (apply (function make-comint) > >> >> - "haskell" "ghci" nil `(,buffer-file-name)))) > >> >> - (pop-to-buffer-same-window "*haskell*")) > >> >> + (pop-to-buffer-same-window ;really in the same window? > >> >> + (or > >> >> + (comint-check-proc "*haskell*") > >> >> + (make-comint "*haskell* repl" "ghci" nil buffer-file-name)))) > >> >> + > >> >> > >> >> (defun haskell-ts-haskell-session () > >> >> (get-buffer-process "*haskell*")) > >> >> > >> >> +(defvar eglot-server-programs) ;to avoid the byte-compiler > >> error > >> >> (defun haskell-ts-setup-eglot() > >> >> (when (featurep 'eglot) > >> >> - (add-to-list 'eglot-server-programs > >> >> + ;; Eglot was added to the core along with tree-siter, so there > is > >> >> + ;; no case where tree-sitter is available, but eglot is not. > >> >> + (add-to-list 'eglot-server-programs > >> >> '(haskell-ts-mode . ("haskell-language-server-wrappe= r" > >> >> "--lsp"))))) > >> >> > >> >> +;; Note that you write (eval-when-load 'eglot > >> >> +;; (haskell-ts-setup-eglot)) in README.org, but that doesn't do wh= at > >> >> +;; you want it to. That will modify eglot-server-programs and > >> >> +;; evaluate the result when eglot is loaded. You presumably wante= d > to > >> >> +;; use `with-eval-after-load'? > >> >> + > >> >> (when (treesit-ready-p 'haskell) > >> >> (add-to-list 'auto-mode-alist '("\\.hs\\'" . haskell-ts-mode))) > >> >> > >> >> (provide 'haskell-ts-mode) > >> >> > >> >> ;;; haskell-ts-mode.el ends here > >> >> - > >> >> > >> >> (Also, a general question, do you use LLMs to generate some of the > >> code?) > >> >> > >> >> > > >> >> > The attached patch is for the elpa repo > >> >> > Thanks, > >> >> > Pranshu > >> >> > diff --git a/elpa-packages b/elpa-packages > >> >> > index 137fef0348..451a67d395 100644 > >> >> > --- a/elpa-packages > >> >> > +++ b/elpa-packages > >> >> > @@ -368,6 +368,9 @@ > >> >> > (gtags-mode :url "https://github.com/Ergus/gtags-mode") > >> >> > (guess-language :url " > >> >> https://github.com/tmalsburg/guess-language.el" > >> >> > :merge t) > >> >> > + (haskell-ts-mode :url " > >> >> https://codeberg.org/pranshu/haskell-ts-mode" > >> >> > + :doc "README.org" > >> >> > >> >> Are you sure that you want the README to be installed as a manual? > >> >> > >> >> > + :ignored-files ("*.png" "LICENSE")) > >> >> > >> >> You can list the files you wish to ignore in an .elpaignore file in > your > >> >> repository; its preferable to using :ignored-files as it is more > >> >> flexible and easier to adjust if something changes on your end. > >> >> > >> >> > (hcel :url "https://g.ypei.me/hc.el.git") > >> >> > (heap :url nil) ;" > >> >> http://www.dr-qubit.org/git/predictive.git" > >> >> > (hiddenquote :url " > >> >> https://gitlab.com/mauroaranda/hiddenquote/hiddenquote") > >> >> > > >> >> > >> >> -- > >> >> Philip Kaludercic on peregrine > >> >> > >> > >> -- > >> Philip Kaludercic on peregrine > >> > > -- > Philip Kaludercic on peregrine > --000000000000e108cd0620d0575c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Oh well, haskell-tng-mode is gpl, and I wouldn't= =C2=A0consider the contributions 'significant', but I think adding = package to=C2=A0 NonGNU elpa would be best to avoid drama.

One day we might find the mythical prof that teaches his students = elisp, till then stay optimistic.

btw, I had to pu= ll back your suggested changes to the run haskell function, they did not wo= rk

On Thu, Aug 29, 2024 at 8:27=E2=80=AFPM Philip Kaludercic <philipk@posteo.net> wrote:
Pranshu Sharma <sirsharmapranshu= @gmail.com> writes:

> Oh yeah, I just realised that and fixed the electric pair mode error.<= br>
1+

> The seq-do part I did not code myself, I copied it from haskell-tng-mo= de,
> as stated in the comment.

That reminds me, haskell-tng-mode is on NonGNU ELPA, but your patch
appears to be for GNU ELPA.=C2=A0 If you code is based on haskell-tng-mode,=
then there might be licensing issues.=C2=A0 Should we add the package to NonGNU ELPA instead, or can you attest to having no significant
contributions from anyone else?

> Homework? students? do you teach your students elisp?

Ugh, no sorry for the misunderstanding.=C2=A0 I was a TA for systems
programming and taught C.=C2=A0 My point was that LLMs tended to generate unusual C code.=C2=A0 I just have weird sensibilities since then.

> On Thu, Aug 29, 2024 at 7:07=E2=80=AFPM Philip Kaludercic <philipk@posteo.net>=
> wrote:
>
>> Pranshu Sharma <sirsharmapranshu@gmail.com> writes:
>>
>> > Hello Phlip,
>> >
>> > Thanks for the edits, I applied all of it apart from when whe= n you want
>> > defun changed to macro, that does not work, as closures are n= ot properly
>> > supported by treesit.
>>
>> OK, sorry about the last suggestion then, as I said, I am not fami= liar
>> with treesitter.
>>
>> > With the spacing, I did what you suggested then used emacs to= indent the
>> > whole page, and added elpaignore file
>>
>> 1+
>>
>> Note that `electric-pair-pairs' is now malconstructed.=C2=A0 I= t is a list of
>> lists, where each list begins with the symbol `cons'.=C2=A0 No= t a list of
>> cons-cells holding two characters.
>>
>> > Also no, I did not use Ai, what made you think so?
>>
>> There were a some unusual constructs repeated a number of times th= at I
>> have never seen before (the way you used seq-do was the main examp= le).
>> It reminded me of homework submissions I have seen students submit= that
>> /were/ AI generated.
>>
>> >
>> > On Thu, Aug 29, 2024 at 1:18=E2=80=AFAM Philip Kaludercic <= ;philipk@posteo.net= >
>> > wrote:
>> >
>> >> Pranshu Sharma <sirsharmapranshu@gmail.com> writes:
>> >>
>> >> > Hello all
>> >> >
>> >> > haskell-ts-mode is a major mode for haskell that use= s treesitter to
>> >> provide
>> >> > features such as indentation and colouring. The mode= can be found at
>> >> > pranshu/haskell-ts-mode:
>> >> > A haskelll mode that uses treesitter - Codeberg.org<= br> >> >> > <https://codeberg.org/pranshu/= haskell-ts-mode>.
>> >>
>> >> First of all, the spacing and indentation is inconsistent= .=C2=A0 Please
>> >> address that, and perhaps add a directory local option to= enforce
>> >> indentation with spaces to ensure a consistent look.
>> >>
>> >> I cannot comment on the tree-sitter stuff since I don'= ;t really
>> >> understand it, but otherwise I have a few comments that I= would like you
>> >> to consider:
>> >>
>> >> diff --git a/haskell-ts-mode.el b/haskell-ts-mode.el
>> >> index 4ba7f42..391db66 100644
>> >> --- a/haskell-ts-mode.el
>> >> +++ b/haskell-ts-mode.el
>> >> @@ -2,7 +2,6 @@
>> >>
>> >>=C2=A0 ;; Copyright (C) 2024=C2=A0 Pranshu Sharma
>> >>
>> >> -
>> >>=C2=A0 ;; Author: Pranshu Sharma <pranshusharma366 at g= mail>
>> >>=C2=A0 ;; URL: https://codeberg.org/pra= nshu/haskell-ts-mode
>> >>=C2=A0 ;; Package-Requires: ((emacs "29.3"))
>> >> @@ -23,6 +22,7 @@
>> >>=C2=A0 ;; along with this program.=C2=A0 If not, see <<= br> >> https://www.gnu.org/licenses/>.
>> >>
>> >>=C2=A0 ;;; Commentary:
>> >> +
>> >>=C2=A0 ;; This is a WIP mode that uses treesitter to provi= de all the basic
>> >>=C2=A0 ;; major mode stuff, like indentation, font lock, e= tc...
>> >>
>> >> @@ -31,6 +31,7 @@
>> >>=C2=A0 (require 'comint)
>> >>=C2=A0 (require 'treesit)
>> >>
>> >> +;; From what I understand this is necessary for tree-sit= ter modes, but
>> >> can you at least also add the ARGLIST argument.=C2=A0 Als= o, some functions
>> such
>> >> as `treesit-induce-sparse-tree' appear not to be used= ?
>> >>=C2=A0 (declare-function treesit-parser-create "trees= it.c")
>> >>=C2=A0 (declare-function treesit-induce-sparse-tree "= treesit.c")
>> >>=C2=A0 (declare-function treesit-node-child "treesit.= c")
>> >> @@ -46,10 +47,11 @@
>> >>=C2=A0 =C2=A0 =C2=A0 (otherwise signature)))
>> >>
>> >>=C2=A0 (defvar haskell-ts-use-indent t
>> >> -=C2=A0 "Set to nil if you don't want to use Ema= cs indent.")
>> >> +=C2=A0 "Set to nil if you don't want to use Ema= cs indent.") ;rephrase this
>> >> would the double negation
>> >>
>> >>=C2=A0 (defvar haskell-ts-font-lock-level 4
>> >>=C2=A0 =C2=A0 "Level of font lock, 1 for minimum high= lghting and 4 for maximum.")
>> >> +;; both of these variables are actually user options and= should be
>> >> declared using `'defcustom'!
>> >>
>> >>=C2=A0 (defvar haskell-ts-prettify-symbols-alits
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 '(("\\" . "= =CE=BB")
>> >> @@ -60,6 +62,7 @@
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0("<=3D" . &= quot;=E2=89=A5")
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(">=3D" . &= quot;=E2=89=A4")))
>> >>
>> >> +;; Checkdoc complains that
>> >>=C2=A0 (defun haskell-ts-font-lock ()
>> >>=C2=A0 =C2=A0 =C2=A0 (treesit-font-lock-rules
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:language 'haskell >> >> @@ -157,7 +160,7 @@
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((parent-is &quo= t;apply") parent -1)
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((node-is "= quasiquote") grand-parent 2)
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((parent-is &quo= t;quasiquote_body") (lambda (_ _ c) c) 0)
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; Do Hg
>> >> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; Do Hg=C2=A0 ;; wha= t does "Hg" mean?
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((lambda (node p= arent bol)
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(le= t ((n (treesit-node-prev-sibling node)))
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0(while (string=3D "comment" (treesit-node-type n))
>> >> @@ -232,6 +235,7 @@
>> >>
>> >>=C2=A0 ;; Copied from haskell-tng-mode, changed a bit
>> >>=C2=A0 (defvar haskell-ts-mode-syntax-table
>> >> +=C2=A0 ;; Should this be wrapped in an `eval-when-compil= e'?
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((table (make-syntax-tabl= e)))
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(map-char-table
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda (k v)
>> >> @@ -241,7 +245,7 @@
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0(modify-syntax-entry k "_" table))))
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (char-table-parent tabl= e))
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; whitechar
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0(seq-do
>> >> +=C2=A0 =C2=A0 =C2=A0 =C2=A0(seq-do=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;seq-d= o has a relatively high
>> >> overhead, try to avoid it
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda (it) (modify-sy= ntax-entry it " " table))
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (string-to-list "\= r\n\f\v \t"))
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; ascSymbol
>> >> @@ -268,46 +272,40 @@
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(modify-syntax-entry ?\{= =C2=A0 "(}1nb" table)
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(modify-syntax-entry ?\}= =C2=A0 "){4nb" table)
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(modify-syntax-entry ?-= =C2=A0 "_ 123" table) ;; TODO --> is not a
>> >> comment
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0(seq-do
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda (it) (modify-syntax-= entry it ">" table))
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 (string-to-list "\r\n\f= \v"))
>> >> +=C2=A0 =C2=A0 =C2=A0 =C2=A0(dolist (c (string-to-list &q= uot;\r\n\f\v")) ;though unrolling
>> wouldn't
>> >> be bad either
>> >> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(modify-syntax-entry c= ">" table))
>> >> +
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0table))
>> >>
>> >> +(defun haskell-ts-imenu-name-function (check-func)
>> >> +=C2=A0 (lambda (node)
>> >> +=C2=A0 =C2=A0 (if (funcall check-func node)
>> >> +=C2=A0 =C2=A0 =C2=A0 =C2=A0(haskell-ts-defun-name node)<= br> >> >> +=C2=A0 =C2=A0 =C2=A0 nil)))
>> >>
>> >> -(defmacro haskell-ts-imenu-name-function (check-func) >> >> -=C2=A0 `(lambda (node)
>> >> -=C2=A0 =C2=A0 =C2=A0 (if (funcall ,check-func node)
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(haskell-ts-defun-name= node)
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0nil)))
>> >> -
>> >> -(defun haskell-ts-indent-para()
>> >> +(defun haskell-ts-indent-para ()
>> >>=C2=A0 =C2=A0 "Indent the current paragraph." >> >>=C2=A0 =C2=A0 (interactive)
>> >> -=C2=A0 (save-excursion
>> >> -=C2=A0 =C2=A0 (backward-paragraph)
>> >> -=C2=A0 =C2=A0 (let ((p (point)))
>> >> -=C2=A0 =C2=A0 =C2=A0 (forward-paragraph)
>> >> -=C2=A0 =C2=A0 =C2=A0 (indent-region p (point)))))
>> >> +=C2=A0 (when-let ((par (bounds-of-thing-at-point 'pa= ragraph)))
>> >> +=C2=A0 =C2=A0 (indent-region (car par) (cdr par))))
>> >>
>> >>=C2=A0 (defvar haskell-ts-mode-map
>> >>=C2=A0 =C2=A0 (let ((km (make-sparse-keymap)))
>> >>=C2=A0 =C2=A0 =C2=A0 (define-key km (kbd "C-c C-c&quo= t;) 'haskell-ts-compile-region-and-go)
>> >>=C2=A0 =C2=A0 =C2=A0 (define-key km (kbd "C-c C-r&quo= t;) 'haskell-ts-run-haskell)
>> >> -=C2=A0 =C2=A0 (define-key km (kbd "C-M-q") = 9;haskell-ts-indent-para)
>> >> +=C2=A0 =C2=A0 (define-key km (kbd "C-M-q") = 9;haskell-ts-indent-para) ;is this
>> >> necessary when `prog-fill-reindent-defun' is bound to= M-q?
>> >>=C2=A0 =C2=A0 =C2=A0 km)
>> >> -=C2=A0 "Map for haskell-ts-mode")
>> >> +=C2=A0 "Map for haskell-ts-mode.")
>> >>
>> >>=C2=A0 ;;;###autoload
>> >>=C2=A0 (define-derived-mode haskell-ts-mode prog-mode &quo= t;haskell ts mode"
>> >>=C2=A0 =C2=A0 "Major mode for Haskell files using tre= e-sitter."
>> >> -=C2=A0 :syntax-table haskell-ts-mode-syntax-table
>> >> -=C2=A0 :interactive t
>> >>=C2=A0 =C2=A0 (unless (treesit-ready-p 'haskell)
>> >>=C2=A0 =C2=A0 =C2=A0 (error "Tree-sitter for Haskell = is not available"))
>> >>=C2=A0 =C2=A0 (treesit-parser-create 'haskell)
>> >>=C2=A0 =C2=A0 (setq-local treesit-defun-type-regexp
>> >> "\\(?:\\(?:function\\|struct\\)_definition\\)")=
>> >>=C2=A0 =C2=A0 ;; Indent
>> >> -=C2=A0 (and haskell-ts-use-indent
>> >> +=C2=A0 (and haskell-ts-use-indent=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0;do you mean `when'?
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq-local treesit-simp= le-indent-rules haskell-ts-indent-rules)
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq-local indent-tabs-= mode nil))
>> >>=C2=A0 =C2=A0 ;; Comment
>> >> @@ -316,21 +314,21 @@
>> >>=C2=A0 =C2=A0 (setq-local comment-start-skip "\\(?: \= \|^\\)-+")
>> >>=C2=A0 =C2=A0 ;; Elecric
>> >>=C2=A0 =C2=A0 (setq-local electric-pair-pairs
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(list (c= ons ?` ?`) (cons ?\( ?\)) (cons ?{ ?}) (cons ?\"
>> >> ?\") (cons ?\[ ?\])))
>> >> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'((?= ` . ?`) (?\( . ?\)) (?{ . ?}) (?\" . ?\") (?\[ .
>> ?\])))
>> >>=C2=A0 =C2=A0 ;; Nav
>> >> -=C2=A0 (setq-local treesit-defun-name-function 'hask= ell-ts-defun-name)
>> >> +=C2=A0 (setq-local treesit-defun-name-function #'has= kell-ts-defun-name)
>> >>=C2=A0 =C2=A0 (setq-local treesit-defun-type-regexp "= function")
>> >>=C2=A0 =C2=A0 (setq-local prettify-symbols-alist haskell-t= s-prettify-symbols-alits)
>> >>=C2=A0 =C2=A0 ;; Imenu
>> >>=C2=A0 =C2=A0 (setq-local treesit-simple-imenu-settings >> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0`((= nil haskell-ts-imenu-func-node-p nil
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 ,(haskell-ts-imenu-name-function
>> >> 'haskell-ts-imenu-func-node-p))
>> >> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 ,(haskell-ts-imenu-name-function
>> >> #'haskell-ts-imenu-func-node-p))
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0("Signatures.." haskell-ts-imenu-sig-node-p nil
>> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = ,(haskell-ts-imenu-name-function
>> >> 'haskell-ts-imenu-sig-node-p))
>> >> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = ,(haskell-ts-imenu-name-function
>> >> #'haskell-ts-imenu-sig-node-p))
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0("Data..." haskell-ts-imenu-data-type-p nil
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 (lambda (node)
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 (treesit-node-text (treesit-node-child node 1))))))
>> >> -=C2=A0 ;; font-lock.
>> >> +=C2=A0 ;; font-lock
>> >>=C2=A0 =C2=A0 (setq-local treesit-font-lock-level haskell-= ts-font-lock-level)
>> >>=C2=A0 =C2=A0 (setq-local treesit-font-lock-settings (hask= ell-ts-font-lock))
>> >>=C2=A0 =C2=A0 (setq-local treesit-font-lock-feature-list >> >> @@ -379,23 +377,32 @@
>> >>
>> >>=C2=A0 (defun haskell-ts-run-haskell()
>> >>=C2=A0 =C2=A0 (interactive)
>> >> -=C2=A0 (when (not (comint-check-proc "*haskell*&quo= t;))
>> >> -=C2=A0 =C2=A0 (set-buffer (apply (function make-comint)<= br> >> >> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 "haskell" "ghci" nil `(,buffer-fil= e-name))))
>> >> -=C2=A0 (pop-to-buffer-same-window "*haskell*")= )
>> >> +=C2=A0 (pop-to-buffer-same-window=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0;really in the same window?
>> >> +=C2=A0 =C2=A0(or
>> >> +=C2=A0 =C2=A0 (comint-check-proc "*haskell*")<= br> >> >> +=C2=A0 =C2=A0 (make-comint "*haskell* repl" &q= uot;ghci" nil buffer-file-name))))
>> >> +
>> >>
>> >>=C2=A0 (defun haskell-ts-haskell-session ()
>> >>=C2=A0 =C2=A0 (get-buffer-process "*haskell*"))<= br> >> >>
>> >> +(defvar eglot-server-programs)=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0;to avoid the byte-compiler
>> error
>> >>=C2=A0 (defun haskell-ts-setup-eglot()
>> >>=C2=A0 =C2=A0 (when (featurep 'eglot)
>> >> -=C2=A0 =C2=A0(add-to-list 'eglot-server-programs
>> >> +=C2=A0 =C2=A0 ;; Eglot was added to the core along with = tree-siter, so there is
>> >> +=C2=A0 =C2=A0 ;; no case where tree-sitter is available,= but eglot is not.
>> >> +=C2=A0 =C2=A0 (add-to-list 'eglot-server-programs >> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &#= 39;(haskell-ts-mode . ("haskell-language-server-wrapper"
>> >> "--lsp")))))
>> >>
>> >> +;; Note that you write (eval-when-load 'eglot
>> >> +;; (haskell-ts-setup-eglot)) in README.org, but that doe= sn't do what
>> >> +;; you want it to.=C2=A0 That will modify eglot-server-p= rograms and
>> >> +;; evaluate the result when eglot is loaded.=C2=A0 You p= resumably wanted to
>> >> +;; use `with-eval-after-load'?
>> >> +
>> >>=C2=A0 (when (treesit-ready-p 'haskell)
>> >>=C2=A0 =C2=A0 (add-to-list 'auto-mode-alist '(&quo= t;\\.hs\\'" . haskell-ts-mode)))
>> >>
>> >>=C2=A0 (provide 'haskell-ts-mode)
>> >>
>> >>=C2=A0 ;;; haskell-ts-mode.el ends here
>> >> -
>> >>
>> >> (Also, a general question, do you use LLMs to generate so= me of the
>> code?)
>> >>
>> >> >
>> >> > The attached patch is for the elpa repo
>> >> > Thanks,
>> >> > Pranshu
>> >> > diff --git a/elpa-packages b/elpa-packages
>> >> > index 137fef0348..451a67d395 100644
>> >> > --- a/elpa-packages
>> >> > +++ b/elpa-packages
>> >> > @@ -368,6 +368,9 @@
>> >> >=C2=A0 =C2=A0(gtags-mode=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0:url "https://github.com/Ergus/gtags-mode") >> >> >=C2=A0 =C2=A0(guess-language=C2=A0 =C2=A0 =C2=A0:url = "
>> >> https://github.com/tmalsburg/guess-l= anguage.el"
>> >> >=C2=A0 =C2=A0 :merge t)
>> >> > + (haskell-ts-mode=C2=A0 =C2=A0 =C2=A0 =C2=A0:url &q= uot;
>> >> https://codeberg.org/pranshu/haskell-t= s-mode"
>> >> > +=C2=A0 :doc "README.org"
>> >>
>> >> Are you sure that you want the README to be installed as = a manual?
>> >>
>> >> > +=C2=A0 :ignored-files ("*.png" "LICE= NSE"))
>> >>
>> >> You can list the files you wish to ignore in an .elpaigno= re file in your
>> >> repository; its preferable to using :ignored-files as it = is more
>> >> flexible and easier to adjust if something changes on you= r end.
>> >>
>> >> >=C2=A0 =C2=A0(hcel=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:url "https://g.ypei= .me/hc.el.git")
>> >> >=C2=A0 =C2=A0(heap=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:url nil) ;"
>> >> http://www.dr-qubit.org/git/predictive.g= it"
>> >> >=C2=A0 =C2=A0(hiddenquote=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 :url "
>> >> https://gitlab.com/mauroaran= da/hiddenquote/hiddenquote")
>> >> >
>> >>
>> >> --
>> >>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Philip Kaludercic on per= egrine
>> >>
>>
>> --
>>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Philip Kaludercic on peregrine >>

--
=C2=A0 =C2=A0 =C2=A0 =C2=A0 Philip Kaludercic on peregrine
--000000000000e108cd0620d0575c--