<commit_before>(in-package :wf/web)

(define-ps-lib displayables ()
  (ps

    (setf tool-tip (@ (require "react-portal-tooltip") default))

    ;;FIXME: Overall use of url, external-link, warflagger-link is inconsistent.
    (def-component target-title
        (psx
         (:div
          :... (format-styling-data (@ this props))
          (:h3
           :class (strcat (flavor-from-own-warstats (prop warstats root))
                          "-old target-title")
           (or (prop intro-text) "Target Page: ")
           (:headline :key 1
                      :title (prop title)
                      :url (prop warflagger-link)
                      :external-link (prop url))
           (:display-warstats2 :key 2)
           (prop children)
           (unless (prop hide-reply)
             (psx (:reply-link
                   :key 3
                   :url (prop url)
                   :excerpt (prop reply-excerpt)
                   :offset (prop reply-offset))))
           (when (prop show-count)
             (psx (:reply-count :key 4 :warstats (prop warstats root))))))))

    (defun popup-side (position)
      (if position
          (if (< (* (chain -math (abs (@ position right))) 2)
                 (chain -math (abs (@ position left))))
              "right"
              "left")
          "left"))

    (defun %find-parent-hilited (element)
      (if element
          (if (equal "hilited" (@ element class-name))
              element
              (%find-parent-hilited (@ element parent-element)))))

    (defun is-selection-in-single-hilited-text? (selection)
      (let ((parent1 (%find-parent-hilited (@ selection anchor-node))))
        (and (not (@ selection is-collapsed))
             parent1
             (eq parent1 (%find-parent-hilited (@ selection focus-node))))))

    (def-component hilited-segment
        (psx
         (:span
          :id (prop id)
          :style (create font-weight :bold position :relative)
          :class (apply #'flavor (prop warstats) (prop excerpt-opinions))
          :on-mouse-enter (@ this handle-mouse-enter)
          :on-mouse-leave (@ this handle-mouse-leave)
          :ref
          (lambda (el)
            (when el
              (let ((res (position-difference
                          (chain document (get-element-by-id (prop hilited-text-id)))
                          el)))
                (unless (chain _ (is-equal (state position) res))
                  (set-state position res)))))
          (rebreak (prop text))
          (:span :class "segment-count" :key (unique-id)
                 (let ((count (%get-replies-count (prop excerpt-opinions) (@ this props))))
                   (if (< 1 count) count "")))
          (:tool-tip :key "a1"
                     :style (popup-style)
                     :active (and (state viewable) (not (prop hide-popup)))
                     :position "bottom"
                     :group "one"
                     :arrow (popup-side (state position))
                     :parent (strcat "#" (prop id))
                     (:sub-opinion-list :... (@ this props)))))
      get-initial-state
      (lambda () (create viewable false position nil))
      handle-mouse-enter
      (lambda (e)
        (when (prop dispatch)
          (funcall (prop dispatch)
                   (create :type 'set-indicated
                           :data
                           (immediate-children-ids (prop id-of-text) (prop opinion-store)))))
        (set-state viewable true))
      handle-mouse-leave
      (lambda (e)
        (when (prop dispatch)
          (funcall (prop dispatch)
                   (create :type 'clear-indicated
                           :data
                           (immediate-children-ids (prop id-of-text) (prop opinion-store)))))
        (set-state viewable false)))

    (def-component plain-segment
        (psx
         (:span :style (create font-weight :normal)
                (rebreak (prop text)))))

    (def-component parent-segment
        (let ((focussed (focus-parent-p (@ this props))))
          (psx
           (:span :style (create font-weight :bold position :relative)
                  :class (if focussed "parent-active" "parent-inactive")
                  :key (unique-id)
                  (rebreak (prop text))
                  (when (and nil ;;Disable for  now
                             focussed
                             (eql (prop last-char-pos)
                                  (+ (@ focussed 0 text-position 0)
                                     (@ focussed 0 text-position 1))))
                    ;;FIXME: obsolete
                    (psx (:opinion :opinions focussed
                                   :key (unique-id)
                                   :focus (prop focus)
                                   :focusfunc (prop focusfunc)
                                   :looks (prop looks)
                                   :look-handler (prop look-handler)
                                   :tree-address (prop tree-address))))))))

    (defun %make-segments (text props)
      (collecting
          (let* ((current-id (when (@ props tree-address)
                               (list-last (@ props tree-address))))
                 (opstore (@ props opinion-store))
                 (opins (immediate-children-ids current-id opstore))
                 (segpoints (excerpt-segment-points
                             (collecting
                                 (dolist (id opins)
                                   (let ((opin (getprop opstore id)))
                                     (when (has-found-excerpt-p opin)
                                       (collect opin)))))
                             (length text))))
            (do-window ((start end) segpoints)
              (let* ((id (strcat "lvl-"
                          (chain props
                                 tree-address length (to-string))
                          "-pos-"
                          (chain end (to-string))))
                     (common-data
                      (create 'excerpt-opinions
                              (remove-if-not
                               (lambda (id)
                                 (let ((opin (getprop opstore id)))
                                   (and (has-found-excerpt-p opin)
                                        (%overlap-p
                                         start (1- end)
                                         (@ opin 'text-position 0)
                                         (+ (@ opin 'text-position 0)
                                            (@ opin 'text-position 1) (- 1))))))
                               opins)
                              :key id
                              :id id
                              :text (chain text (slice start end))
                              :id-of-text current-id
                              :focusfunc (@ props focusfunc)
                              :looks (@ props looks)
                              :warstats (@ props warstats)
                              :references (@ props references)
                              'opinion-store (@ props opinion-store)
                              'hilited-text-id (@ props hilited-text-id)
                              'root-target-url (@ props root-target-url)
                              'look-handler (@ props look-handler)
                              'hide-popup (@ props hide-popup)
                              :dispatch (@ props dispatch)
                              tree-address (@ props tree-address))))
              (cond ((< (@ common-data 'excerpt-opinions length) 1)
                       (collect
                           (psx (:plain-segment
                                 :... common-data))))
                      ((focus-p props)
                       (collect
                           (psx (:hilited-segment
                                 :... common-data))))
                      (t
                       (collect
                           (psx (:parent-segment
                                 :... common-data
                                 :focus (@ props focus)
                                 :last-char-pos end))))))))))

    (def-component hilited-text
        (psx
         (:div
          :class
          (if (focus-p (@ this props)) "hilited" "hilited-parent")
          :key (state id)
          :id (state id)
          :on-click (lambda (e) (chain e (stop-propagation)))
          :on-mouse-up (@ this selection-change)
          :on-key-press (@ this selection-change)
          (when (prop text)
            (%make-segments (prop text)
                            (set-copy (@ this props)
                                      'hilited-text-id
                                      (state id))))))
      get-initial-state
      (lambda ()
        (create :id (strcat "hilited-text-" (unique-id))))
      selection-change
      (lambda (ev)
        (when (prop dispatch)
          (if (is-selection-in-single-hilited-text? (chain rangy (get-selection)))
            (let* ((textel (chain document (get-element-by-id (state id))))
                   (range (chain rangy (get-selection) (get-range-at 0)
                                 (to-character-range textel)))
                   (excerpt (get-location-excerpt (create-textdata (prop text))
                                                  (@ range start) (@ range end))))
              (funcall
               (prop dispatch)
               (create :type :selection<commit_msg>Attempt to fix the reply to excerpt off by 1<commit_after>(in-package :wf/web)

(define-ps-lib displayables ()
  (ps

    (setf tool-tip (@ (require "react-portal-tooltip") default))

    ;;FIXME: Overall use of url, external-link, warflagger-link is inconsistent.
    (def-component target-title
        (psx
         (:div
          :... (format-styling-data (@ this props))
          (:h3
           :class (strcat (flavor-from-own-warstats (prop warstats root))
                          "-old target-title")
           (or (prop intro-text) "Target Page: ")
           (:headline :key 1
                      :title (prop title)
                      :url (prop warflagger-link)
                      :external-link (prop url))
           (:display-warstats2 :key 2)
           (prop children)
           (unless (prop hide-reply)
             (psx (:reply-link
                   :key 3
                   :url (prop url)
                   :excerpt (prop reply-excerpt)
                   :offset (prop reply-offset))))
           (when (prop show-count)
             (psx (:reply-count :key 4 :warstats (prop warstats root))))))))

    (defun popup-side (position)
      (if position
          (if (< (* (chain -math (abs (@ position right))) 2)
                 (chain -math (abs (@ position left))))
              "right"
              "left")
          "left"))

    (defun %find-parent-hilited (element)
      (if element
          (if (equal "hilited" (@ element class-name))
              element
              (%find-parent-hilited (@ element parent-element)))))

    (defun is-selection-in-single-hilited-text? (selection)
      (let ((parent1 (%find-parent-hilited (@ selection anchor-node))))
        (and (not (@ selection is-collapsed))
             parent1
             (eq parent1 (%find-parent-hilited (@ selection focus-node))))))

    (def-component hilited-segment
        (psx
         (:span
          :id (prop id)
          :style (create font-weight :bold position :relative)
          :class (apply #'flavor (prop warstats) (prop excerpt-opinions))
          :on-mouse-enter (@ this handle-mouse-enter)
          :on-mouse-leave (@ this handle-mouse-leave)
          :ref
          (lambda (el)
            (when el
              (let ((res (position-difference
                          (chain document (get-element-by-id (prop hilited-text-id)))
                          el)))
                (unless (chain _ (is-equal (state position) res))
                  (set-state position res)))))
          (rebreak (prop text))
          (:span :class "segment-count" :key (unique-id)
                 (let ((count (%get-replies-count (prop excerpt-opinions) (@ this props))))
                   (if (< 1 count) count "")))
          (:tool-tip :key "a1"
                     :style (popup-style)
                     :active (and (state viewable) (not (prop hide-popup)))
                     :position "bottom"
                     :group "one"
                     :arrow (popup-side (state position))
                     :parent (strcat "#" (prop id))
                     (:sub-opinion-list :... (@ this props)))))
      get-initial-state
      (lambda () (create viewable false position nil))
      handle-mouse-enter
      (lambda (e)
        (when (prop dispatch)
          (funcall (prop dispatch)
                   (create :type 'set-indicated
                           :data
                           (immediate-children-ids (prop id-of-text) (prop opinion-store)))))
        (set-state viewable true))
      handle-mouse-leave
      (lambda (e)
        (when (prop dispatch)
          (funcall (prop dispatch)
                   (create :type 'clear-indicated
                           :data
                           (immediate-children-ids (prop id-of-text) (prop opinion-store)))))
        (set-state viewable false)))

    (def-component plain-segment
        (psx
         (:span :style (create font-weight :normal)
                (rebreak (prop text)))))

    (def-component parent-segment
        (let ((focussed (focus-parent-p (@ this props))))
          (psx
           (:span :style (create font-weight :bold position :relative)
                  :class (if focussed "parent-active" "parent-inactive")
                  :key (unique-id)
                  (rebreak (prop text))
                  (when (and nil ;;Disable for  now
                             focussed
                             (eql (prop last-char-pos)
                                  (+ (@ focussed 0 text-position 0)
                                     (@ focussed 0 text-position 1))))
                    ;;FIXME: obsolete
                    (psx (:opinion :opinions focussed
                                   :key (unique-id)
                                   :focus (prop focus)
                                   :focusfunc (prop focusfunc)
                                   :looks (prop looks)
                                   :look-handler (prop look-handler)
                                   :tree-address (prop tree-address))))))))

    (defun %make-segments (text props)
      (collecting
          (let* ((current-id (when (@ props tree-address)
                               (list-last (@ props tree-address))))
                 (opstore (@ props opinion-store))
                 (opins (immediate-children-ids current-id opstore))
                 (segpoints (excerpt-segment-points
                             (collecting
                                 (dolist (id opins)
                                   (let ((opin (getprop opstore id)))
                                     (when (has-found-excerpt-p opin)
                                       (collect opin)))))
                             (length text))))
            (do-window ((start end) segpoints)
              (let* ((id (strcat "lvl-"
                          (chain props
                                 tree-address length (to-string))
                          "-pos-"
                          (chain end (to-string))))
                     (common-data
                      (create 'excerpt-opinions
                              (remove-if-not
                               (lambda (id)
                                 (let ((opin (getprop opstore id)))
                                   (and (has-found-excerpt-p opin)
                                        (%overlap-p
                                         start (1- end)
                                         (@ opin 'text-position 0)
                                         (+ (@ opin 'text-position 0)
                                            (@ opin 'text-position 1) (- 1))))))
                               opins)
                              :key id
                              :id id
                              :text (chain text (slice start end))
                              :id-of-text current-id
                              :focusfunc (@ props focusfunc)
                              :looks (@ props looks)
                              :warstats (@ props warstats)
                              :references (@ props references)
                              'opinion-store (@ props opinion-store)
                              'hilited-text-id (@ props hilited-text-id)
                              'root-target-url (@ props root-target-url)
                              'look-handler (@ props look-handler)
                              'hide-popup (@ props hide-popup)
                              :dispatch (@ props dispatch)
                              tree-address (@ props tree-address))))
              (cond ((< (@ common-data 'excerpt-opinions length) 1)
                       (collect
                           (psx (:plain-segment
                                 :... common-data))))
                      ((focus-p props)
                       (collect
                           (psx (:hilited-segment
                                 :... common-data))))
                      (t
                       (collect
                           (psx (:parent-segment
                                 :... common-data
                                 :focus (@ props focus)
                                 :last-char-pos end))))))))))

    (def-component hilited-text
        (psx
         (:div
          :class
          (if (focus-p (@ this props)) "hilited" "hilited-parent")
          :key (state id)
          :id (state id)
          :on-click (lambda (e) (chain e (stop-propagation)))
          :on-mouse-up (@ this selection-change)
          :on-key-press (@ this selection-change)
          (when (prop text)
            ;;Stray whitespace can confuse location of reply to excerpt, hence the trim
            (%make-segments (chain (prop text) (trim))
                            (set-copy (@ this props)
                                      'hilited-text-id
                                      (state id))))))
      get-initial-state
      (lambda ()
        (create :id (strcat "hilited-text-" (unique-id))))
      selection-change
      (lambda (ev)
        (when (prop dispatch)
          (if (is-selection-in-single-hilited-text? (chain rangy (get-selection)))
            (let* ((textel (chain document (get-element-by-id (state id))))
                   (range (chain rangy (get-selection) (get-range-at 0)
                                 (to-character-range textel)))
                   (excerpt (get-location-excerpt (create-textdata (prop text))
                                                  (@ range start) (@ range end))))
              (funcall
               (prop dispatch)
               (create :type :selection
{'fraction_non_alphanumeric': 0.11301049568741557, 'fraction_numerical': 0.0024420658838200143, 'mean_word_length': 1.044942626434339, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 68, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '741802', 'n_tokens_mistral': 4857, 'n_tokens_neox': 4562, 'n_words': 1222}