update packages
This commit is contained in:
@@ -24,7 +24,23 @@
|
||||
;;; Code:
|
||||
(eval-and-compile (require 'org-macs))
|
||||
(eval-and-compile (require 'ol))
|
||||
(require 'hydra)
|
||||
|
||||
;; Declare functions from org-element
|
||||
(declare-function org-element-context "org-element" (&optional element))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-parse-buffer "org-element" (&optional granularity visible-only))
|
||||
(declare-function org-element-map "org-element" (data types fun &optional info first-match no-recursion with-affiliated))
|
||||
(declare-function org-element-interpret-data "org-element" (data))
|
||||
|
||||
;; Declare functions from org
|
||||
(declare-function org-mark-ring-push "org" (&optional pos buffer))
|
||||
(declare-function org-file-image-p "org" (file &optional extensions))
|
||||
(declare-function org-at-table-p "org" (&optional table-type))
|
||||
(declare-function org-table-begin "org" (&optional table-type))
|
||||
|
||||
;; Declare functions from ox (org-export)
|
||||
(declare-function org-export-get-caption "ox" (element &optional short))
|
||||
|
||||
(defcustom org-ref-default-ref-type "ref"
|
||||
"Default ref link type to use when inserting ref links."
|
||||
@@ -40,6 +56,36 @@ links. Set this to nil to turn off activation."
|
||||
:group 'org-ref)
|
||||
|
||||
|
||||
(defcustom org-ref-show-equation-images-in-tooltips nil
|
||||
"If non-nil, show rendered equation images in tooltips for equation references.
|
||||
Requires that equations have been previewed with `org-latex-preview' or
|
||||
a compatible preview package (like math-preview).
|
||||
|
||||
When enabled, hovering over an equation reference (eqref, ref, etc.) will
|
||||
display the rendered equation image in a tooltip instead of raw LaTeX code.
|
||||
|
||||
This feature works best in GUI Emacs. In terminal Emacs, falls back to
|
||||
text display."
|
||||
:type 'boolean
|
||||
:group 'org-ref)
|
||||
|
||||
|
||||
(defcustom org-ref-enable-multi-file-references t
|
||||
"If non-nil, collect labels from files included via #+INCLUDE directives.
|
||||
|
||||
When enabled, org-ref will search for labels not only in the current buffer,
|
||||
but also in all files referenced via #+INCLUDE directives. This allows
|
||||
cross-references to work across multiple files in a project.
|
||||
|
||||
Labels are cached per-file and only re-scanned when files change, using
|
||||
timestamp-based change detection for performance.
|
||||
|
||||
For single-file documents, this feature has minimal overhead since no
|
||||
#+INCLUDE directives are present. Set to nil to disable if needed."
|
||||
:type 'boolean
|
||||
:group 'org-ref)
|
||||
|
||||
|
||||
(defface org-ref-ref-face
|
||||
`((t (:inherit org-link :foreground "dark red")))
|
||||
"Face for ref links in org-ref."
|
||||
@@ -132,6 +178,162 @@ The label should always be in group 1.")
|
||||
"Buffer-local variable to hold `buffer-chars-modified-tick'.")
|
||||
|
||||
|
||||
(defvar-local org-ref-preview-image-cache nil
|
||||
"Buffer-local cache of (label . image-spec) for preview images.")
|
||||
|
||||
|
||||
(defvar-local org-ref-preview-cache-tick nil
|
||||
"Buffer modification tick when preview image cache was last updated.")
|
||||
|
||||
|
||||
;; Multi-file reference support - global caches
|
||||
(defvar org-ref-project-label-cache (make-hash-table :test 'equal)
|
||||
"Hash table mapping project-root -> ((file . labels-alist) ...).
|
||||
Used when `org-ref-enable-multi-file-references' is non-nil to cache
|
||||
labels from multiple files in a project.")
|
||||
|
||||
|
||||
(defvar org-ref-file-timestamps (make-hash-table :test 'equal)
|
||||
"Hash table mapping file-path -> (mtime . size) for change detection.
|
||||
Used to determine if a file needs to be re-scanned for labels without
|
||||
actually opening and parsing the file.")
|
||||
|
||||
|
||||
(defun org-ref-get-included-files ()
|
||||
"Return list of absolute paths to files included in current buffer.
|
||||
Parses #+INCLUDE directives and returns a list of existing files.
|
||||
Only returns files that actually exist on disk."
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(let ((files '()))
|
||||
(while (re-search-forward "^[ \t]*#\\+INCLUDE:[ \t]+\"\\([^\"]+\\)\"" nil t)
|
||||
(let* ((file (match-string-no-properties 1))
|
||||
(expanded-file (expand-file-name file)))
|
||||
(when (file-exists-p expanded-file)
|
||||
(push expanded-file files))))
|
||||
(nreverse files))))
|
||||
|
||||
|
||||
(defun org-ref-file-changed-p (file)
|
||||
"Check if FILE has changed since last scan using timestamp and size.
|
||||
This is an O(1) operation that doesn't require parsing the file.
|
||||
Returns t if the file has changed or hasn't been scanned yet."
|
||||
(let* ((attrs (file-attributes file))
|
||||
(mtime (nth 5 attrs))
|
||||
(size (nth 7 attrs))
|
||||
(cached (gethash file org-ref-file-timestamps)))
|
||||
(or (not cached)
|
||||
(not (equal mtime (car cached)))
|
||||
(not (equal size (cdr cached))))))
|
||||
|
||||
|
||||
(defun org-ref-mark-file-scanned (file)
|
||||
"Record timestamp and size of FILE to detect future changes."
|
||||
(let* ((attrs (file-attributes file))
|
||||
(mtime (nth 5 attrs))
|
||||
(size (nth 7 attrs)))
|
||||
(puthash file (cons mtime size) org-ref-file-timestamps)))
|
||||
|
||||
|
||||
(defun org-ref-scan-buffer-for-labels ()
|
||||
"Scan current buffer for labels and return list of (label . context) cons cells.
|
||||
This is the core scanning logic used by both single-file and multi-file modes."
|
||||
(let ((case-fold-search t)
|
||||
(rx (string-join org-ref-ref-label-regexps "\\|"))
|
||||
(labels '())
|
||||
oe ;; org-element
|
||||
context)
|
||||
(save-excursion
|
||||
(org-with-wide-buffer
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward rx nil t)
|
||||
(save-match-data
|
||||
;; Here we try to get some relevant context for different things you
|
||||
;; might reference.
|
||||
(setq oe (org-element-context)
|
||||
context (string-trim
|
||||
(pcase (car oe)
|
||||
('latex-environment (buffer-substring
|
||||
(org-element-property :begin oe)
|
||||
(org-element-property :end oe)))
|
||||
;; figure
|
||||
('paragraph (buffer-substring
|
||||
(org-element-property :begin oe)
|
||||
(org-element-property :end oe)))
|
||||
('table (buffer-substring
|
||||
(org-element-property :begin oe)
|
||||
(org-element-property :end oe)))
|
||||
;; Headings fall here.
|
||||
(_ (buffer-substring (line-beginning-position)
|
||||
(line-end-position)))))))
|
||||
(cl-pushnew (cons (match-string-no-properties 1) context)
|
||||
labels))))
|
||||
;; reverse so they are in the order we find them.
|
||||
(delete-dups (reverse labels))))
|
||||
|
||||
|
||||
(defun org-ref-get-labels-single-file ()
|
||||
"Get labels from current buffer only (original single-file behavior).
|
||||
Uses buffer-local cache and buffer-chars-modified-tick for invalidation."
|
||||
(if (or
|
||||
;; if we have not checked we have to check
|
||||
(null org-ref-buffer-chars-modified-tick)
|
||||
;; Now check if buffer has changed since last time we looked. We check
|
||||
;; this with the buffer-chars-modified-tick which keeps track of changes.
|
||||
;; If this hasn't changed, no chars have been modified.
|
||||
(not (= (buffer-chars-modified-tick)
|
||||
org-ref-buffer-chars-modified-tick)))
|
||||
;; We need to search for all the labels either because we don't have them,
|
||||
;; or the buffer has changed since we looked last time.
|
||||
(setq
|
||||
org-ref-buffer-chars-modified-tick (buffer-chars-modified-tick)
|
||||
org-ref-label-cache (org-ref-scan-buffer-for-labels))
|
||||
;; retrieve the cached data
|
||||
org-ref-label-cache))
|
||||
|
||||
|
||||
(defun org-ref-scan-file-for-labels (file)
|
||||
"Scan FILE for labels and return list of (label . context) cons cells.
|
||||
Opens the file in a temporary buffer and scans it."
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(org-mode)
|
||||
(org-ref-scan-buffer-for-labels)))
|
||||
|
||||
|
||||
(defun org-ref-get-labels-multi-file ()
|
||||
"Get labels from current file and all included files.
|
||||
Only re-scans files that have actually changed (timestamp-based detection).
|
||||
Uses global project cache for efficiency."
|
||||
(when (buffer-file-name)
|
||||
(let* ((current-file (buffer-file-name))
|
||||
(included-files (org-ref-get-included-files))
|
||||
(all-files (cons current-file included-files))
|
||||
(all-labels '()))
|
||||
|
||||
;; For each file, check if it changed and re-scan only if needed
|
||||
(dolist (file all-files)
|
||||
(when (org-ref-file-changed-p file)
|
||||
;; File changed, re-scan it
|
||||
(let ((file-labels (if (string= file current-file)
|
||||
;; For current file, use the regular scan
|
||||
(org-ref-scan-buffer-for-labels)
|
||||
;; For included files, scan from disk
|
||||
(org-ref-scan-file-for-labels file))))
|
||||
;; Cache the labels for this file
|
||||
(puthash file file-labels org-ref-project-label-cache)
|
||||
;; Mark file as scanned
|
||||
(org-ref-mark-file-scanned file)))
|
||||
|
||||
;; Retrieve cached labels for this file
|
||||
(let ((file-labels (gethash file org-ref-project-label-cache)))
|
||||
(when file-labels
|
||||
(setq all-labels (append all-labels file-labels)))))
|
||||
|
||||
;; Remove duplicates (in case same label appears in multiple files)
|
||||
(delete-dups all-labels))))
|
||||
|
||||
|
||||
(defun org-ref-get-labels ()
|
||||
"Return a list of referenceable labels in the document.
|
||||
You can reference:
|
||||
@@ -146,60 +348,48 @@ See `org-ref-ref-label-regexps' for the patterns that find these.
|
||||
|
||||
Returns a list of cons cells (label . context).
|
||||
|
||||
If `org-ref-enable-multi-file-references' is non-nil, also includes
|
||||
labels from files referenced via #+INCLUDE directives.
|
||||
|
||||
It is important for this function to be fast, since we use it in
|
||||
font-lock."
|
||||
(if (or
|
||||
;; if we have not checked we have to check
|
||||
(null org-ref-buffer-chars-modified-tick)
|
||||
;; Now check if buffer has changed since last time we looked. We check
|
||||
;; this with the buffer-chars-modified-tick which keeps track of changes.
|
||||
;; If this hasn't changed, no chars have been modified.
|
||||
(not (= (buffer-chars-modified-tick)
|
||||
org-ref-buffer-chars-modified-tick)))
|
||||
;; We need to search for all the labels either because we don't have them,
|
||||
;; or the buffer has changed since we looked last time.
|
||||
(let ((case-fold-search t)
|
||||
(rx (string-join org-ref-ref-label-regexps "\\|"))
|
||||
(labels '())
|
||||
oe ;; org-element
|
||||
context)
|
||||
(save-excursion
|
||||
(org-with-wide-buffer
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward rx nil t)
|
||||
(save-match-data
|
||||
;; Here we try to get some relevant context for different things you
|
||||
;; might reference.
|
||||
(setq oe (org-element-context)
|
||||
context (string-trim
|
||||
(pcase (car oe)
|
||||
('latex-environment (buffer-substring
|
||||
(org-element-property :begin oe)
|
||||
(org-element-property :end oe)))
|
||||
;; figure
|
||||
('paragraph (buffer-substring
|
||||
(org-element-property :begin oe)
|
||||
(org-element-property :end oe)))
|
||||
('table (buffer-substring
|
||||
(org-element-property :begin oe)
|
||||
(org-element-property :end oe)))
|
||||
;; Headings fall here.
|
||||
(_ (buffer-substring (line-beginning-position)
|
||||
(line-end-position)))))))
|
||||
(cl-pushnew (cons (match-string-no-properties 1) context)
|
||||
labels))))
|
||||
|
||||
;; reverse so they are in the order we find them.
|
||||
(setq
|
||||
org-ref-buffer-chars-modified-tick (buffer-chars-modified-tick)
|
||||
org-ref-label-cache (delete-dups (reverse labels))))
|
||||
(if org-ref-enable-multi-file-references
|
||||
(org-ref-get-labels-multi-file)
|
||||
(org-ref-get-labels-single-file)))
|
||||
|
||||
;; retrieve the cached data
|
||||
org-ref-label-cache))
|
||||
|
||||
(defun org-ref-find-label-in-buffer (label)
|
||||
"Search for LABEL in current buffer.
|
||||
Returns t if found and moves point to the label, nil otherwise."
|
||||
(let ((case-fold-search t)
|
||||
(rx (string-join org-ref-ref-label-regexps "\\|")))
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(catch 'found
|
||||
(while (re-search-forward rx nil t)
|
||||
(when (string= label (match-string-no-properties 1))
|
||||
(goto-char (match-beginning 1))
|
||||
(throw 'found t)))))))
|
||||
|
||||
|
||||
(defun org-ref-find-label-in-file (label file)
|
||||
"Search for LABEL in FILE.
|
||||
Returns the position if found, nil otherwise."
|
||||
(with-current-buffer (find-file-noselect file)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(let ((case-fold-search t)
|
||||
(rx (string-join org-ref-ref-label-regexps "\\|")))
|
||||
(catch 'found
|
||||
(while (re-search-forward rx nil t)
|
||||
(when (string= label (match-string-no-properties 1))
|
||||
(throw 'found (match-beginning 1)))))))))
|
||||
|
||||
|
||||
(defun org-ref-ref-jump-to (&optional path)
|
||||
"Jump to the target for the ref link at point."
|
||||
"Jump to the target for the ref link at point.
|
||||
If `org-ref-enable-multi-file-references' is non-nil and the label
|
||||
is not found in the current buffer, searches in included files."
|
||||
(interactive)
|
||||
(let ((case-fold-search t)
|
||||
(label (get-text-property (point) 'org-ref-ref-label))
|
||||
@@ -213,23 +403,163 @@ font-lock."
|
||||
(setq label (completing-read "Label: " labels)))))
|
||||
(when label
|
||||
(org-mark-ring-push)
|
||||
;; First, try to find in current buffer
|
||||
(widen)
|
||||
(goto-char (point-min))
|
||||
(catch 'found
|
||||
(while (re-search-forward rx)
|
||||
(when (string= label (match-string-no-properties 1))
|
||||
(save-match-data (org-mark-ring-push))
|
||||
(goto-char (match-beginning 1))
|
||||
(org-fold-show-entry)
|
||||
(substitute-command-keys
|
||||
"Go back with (org-mark-ring-goto) \`\\[org-mark-ring-goto]'.")
|
||||
(throw 'found t)))))))
|
||||
(let ((found nil))
|
||||
(catch 'found
|
||||
(while (re-search-forward rx nil t)
|
||||
(when (string= label (match-string-no-properties 1))
|
||||
(save-match-data (org-mark-ring-push))
|
||||
(goto-char (match-beginning 1))
|
||||
(org-fold-show-entry)
|
||||
(message
|
||||
(substitute-command-keys
|
||||
"Go back with (org-mark-ring-goto) \\[org-mark-ring-goto]."))
|
||||
(setq found t)
|
||||
(throw 'found t))))
|
||||
|
||||
;; If not found in current buffer and multi-file mode is enabled,
|
||||
;; search in included files
|
||||
(when (and (not found)
|
||||
org-ref-enable-multi-file-references
|
||||
(buffer-file-name))
|
||||
(let ((included-files (org-ref-get-included-files)))
|
||||
(catch 'found-in-file
|
||||
(dolist (file included-files)
|
||||
(let ((pos (org-ref-find-label-in-file label file)))
|
||||
(when pos
|
||||
;; Found in an included file - open it and jump to position
|
||||
(find-file file)
|
||||
(goto-char pos)
|
||||
(org-fold-show-entry)
|
||||
(message
|
||||
(substitute-command-keys
|
||||
"Go back with (org-mark-ring-goto) \\[org-mark-ring-goto]."))
|
||||
(throw 'found-in-file t)))))
|
||||
|
||||
;; If we get here, label wasn't found anywhere
|
||||
(unless found
|
||||
(message "Label '%s' not found in current file or included files" label))))))))
|
||||
|
||||
|
||||
|
||||
(defun org-ref-find-overlay-with-image (begin end)
|
||||
"Find an overlay with an image display property between BEGIN and END.
|
||||
Returns the image display spec or nil if none found."
|
||||
(catch 'found
|
||||
(let ((pos begin))
|
||||
(while (< pos end)
|
||||
(dolist (ov (overlays-at pos))
|
||||
;; Check for org-mode preview overlay or math-preview overlay
|
||||
(when (or (eq (overlay-get ov 'org-overlay-type) 'org-latex-overlay)
|
||||
(overlay-get ov 'preview-image))
|
||||
(let ((display (overlay-get ov 'display)))
|
||||
(when (and display (listp display) (eq (car display) 'image))
|
||||
(throw 'found display)))))
|
||||
(setq pos (next-overlay-change pos))))
|
||||
nil))
|
||||
|
||||
|
||||
(defun org-ref-get-preview-image-at-label (label)
|
||||
"Return the preview image display spec for LABEL if it exists.
|
||||
Searches for LABEL in the buffer (both \\label{LABEL} and #+name: LABEL forms)
|
||||
and checks if there is an org-latex preview overlay at that location.
|
||||
Returns the image display spec that can be used in a propertized string,
|
||||
or nil if no preview exists.
|
||||
|
||||
Uses caching for performance - cache is invalidated when buffer is modified."
|
||||
;; Check cache first
|
||||
(let ((cached (and org-ref-preview-image-cache
|
||||
(equal org-ref-preview-cache-tick (buffer-chars-modified-tick))
|
||||
(assoc label org-ref-preview-image-cache))))
|
||||
(if cached
|
||||
(cdr cached)
|
||||
;; Not in cache, search for it
|
||||
(let ((image-spec
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(widen)
|
||||
(goto-char (point-min))
|
||||
(or
|
||||
;; Try 1: Search for \label{LABEL} in LaTeX environments
|
||||
(when (re-search-forward (format "\\\\label{%s}" (regexp-quote label)) nil t)
|
||||
(let* ((elem (org-element-context))
|
||||
(begin (org-element-property :begin elem))
|
||||
(end (org-element-property :end elem)))
|
||||
(when (and begin end (eq (org-element-type elem) 'latex-environment))
|
||||
(org-ref-find-overlay-with-image begin end))))
|
||||
|
||||
;; Try 2: Search for #+name: LABEL before latex-environment
|
||||
(progn
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward (format "^[ \t]*#\\+name:[ \t]+%s[ \t]*$"
|
||||
(regexp-quote label)) nil t)
|
||||
(forward-line 1)
|
||||
(let* ((elem (org-element-context))
|
||||
(begin (org-element-property :begin elem))
|
||||
(end (org-element-property :end elem)))
|
||||
(when (and begin end (eq (org-element-type elem) 'latex-environment))
|
||||
(org-ref-find-overlay-with-image begin end))))))))))
|
||||
|
||||
;; Update cache
|
||||
(when (or (null org-ref-preview-cache-tick)
|
||||
(not (equal org-ref-preview-cache-tick (buffer-chars-modified-tick))))
|
||||
(setq org-ref-preview-image-cache nil
|
||||
org-ref-preview-cache-tick (buffer-chars-modified-tick)))
|
||||
|
||||
;; Add to cache (even if nil, to avoid repeated searches)
|
||||
(push (cons label image-spec) org-ref-preview-image-cache)
|
||||
|
||||
image-spec))))
|
||||
|
||||
|
||||
(defun org-ref-ref-help-echo (_win _obj position)
|
||||
"Tooltip for context on a ref label.
|
||||
POSITION is the point under the mouse I think."
|
||||
(cdr (assoc (get-text-property position 'org-ref-ref-label) (org-ref-get-labels))))
|
||||
"Tooltip for context on a ref label with optional image support.
|
||||
POSITION is the point under the mouse.
|
||||
|
||||
Strategy: If previews exist on equations, show them in the minibuffer.
|
||||
Otherwise show text.
|
||||
|
||||
When `org-ref-show-equation-images-in-tooltips' is non-nil and running in
|
||||
GUI Emacs, checks if a preview image exists for the referenced equation.
|
||||
If found, displays the image in the minibuffer using message. Otherwise,
|
||||
displays the LaTeX text context as usual.
|
||||
|
||||
Always returns a string (empty string if no context is found)."
|
||||
(let* ((label (get-text-property position 'org-ref-ref-label))
|
||||
(context (cdr (assoc label (org-ref-get-labels))))
|
||||
(fallback (if label
|
||||
(format "Reference to %s" label)
|
||||
"")))
|
||||
;; Try to show image if conditions are met
|
||||
(or (if (and org-ref-show-equation-images-in-tooltips
|
||||
label
|
||||
(display-graphic-p)) ; Images only work in GUI
|
||||
;; Try to find and display preview image
|
||||
(let ((image-spec (org-ref-get-preview-image-at-label label)))
|
||||
(if image-spec
|
||||
;; Extract file from the overlay's image spec
|
||||
(let ((file (plist-get (cdr image-spec) :file)))
|
||||
;; Only show image if file exists
|
||||
(if (and file (file-exists-p file))
|
||||
(condition-case nil
|
||||
;; Show image in minibuffer using message
|
||||
;; Use the same image-spec from the overlay to preserve size
|
||||
(progn
|
||||
(message "%s" (propertize " " 'display image-spec))
|
||||
;; Still return context for any fallback tooltip
|
||||
context)
|
||||
;; If image display fails, show text
|
||||
(error context))
|
||||
;; File doesn't exist, show text
|
||||
context))
|
||||
;; No image spec found, show text
|
||||
context))
|
||||
;; Feature disabled or not in GUI, show text
|
||||
context)
|
||||
;; Fallback when context is nil
|
||||
fallback)))
|
||||
|
||||
|
||||
(defun org-ref-ref-activate (start _end path _bracketp)
|
||||
@@ -305,10 +635,10 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
;; caption paragraph may have a name which we use if it is there
|
||||
(org-element-property :name parent)
|
||||
;; else search caption
|
||||
(let ((caption (s-join
|
||||
""
|
||||
(let ((caption (string-join
|
||||
(mapcar 'org-no-properties
|
||||
(org-export-get-caption parent)))))
|
||||
(org-export-get-caption parent))
|
||||
"")))
|
||||
(when (string-match org-ref-label-re caption)
|
||||
(match-string 1 caption))))))))
|
||||
|
||||
@@ -319,8 +649,8 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
(org-element-property :name object)
|
||||
|
||||
;; See if it is in the caption name
|
||||
(let ((caption (s-join "" (mapcar 'org-no-properties
|
||||
(org-export-get-caption object)))))
|
||||
(let ((caption (string-join (mapcar 'org-no-properties
|
||||
(org-export-get-caption object)) "")))
|
||||
(when (string-match org-ref-label-re caption)
|
||||
(match-string 1 caption)))))
|
||||
|
||||
@@ -332,7 +662,7 @@ This is meant to be used with `apply-partially' in the link definitions."
|
||||
(goto-char (org-table-begin))
|
||||
(let* ((table (org-element-context))
|
||||
(label (org-element-property :name table))
|
||||
(caption (s-join "" (mapcar 'org-no-properties
|
||||
(caption (string-join "" (mapcar 'org-no-properties
|
||||
(org-export-get-caption table)))))
|
||||
(when (null label)
|
||||
;; maybe there is a label in the caption?
|
||||
|
||||
Reference in New Issue
Block a user