emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to emacs/lisp/textmodes/bibtex.el [emacs-unicode-2


From: Miles Bader
Subject: [Emacs-diffs] Changes to emacs/lisp/textmodes/bibtex.el [emacs-unicode-2]
Date: Mon, 28 Jun 2004 04:36:15 -0400

Index: emacs/lisp/textmodes/bibtex.el
diff -c emacs/lisp/textmodes/bibtex.el:1.77.2.1 
emacs/lisp/textmodes/bibtex.el:1.77.2.2
*** emacs/lisp/textmodes/bibtex.el:1.77.2.1     Fri Apr 16 12:50:37 2004
--- emacs/lisp/textmodes/bibtex.el      Mon Jun 28 07:29:50 2004
***************
*** 1,6 ****
  ;;; bibtex.el --- BibTeX mode for GNU Emacs
  
! ;; Copyright (C) 1992,94,95,96,97,98,1999,2003  Free Software Foundation, Inc.
  
  ;; Author: Stefan Schoef <address@hidden>
  ;;      Bengt Martensson <address@hidden>
--- 1,7 ----
  ;;; bibtex.el --- BibTeX mode for GNU Emacs
  
! ;; Copyright (C) 1992,94,95,96,97,98,1999,2003,2004
! ;;           Free Software Foundation, Inc.
  
  ;; Author: Stefan Schoef <address@hidden>
  ;;      Bengt Martensson <address@hidden>
***************
*** 811,816 ****
--- 812,818 ----
      (define-key km "\C-c\M-y" 'bibtex-yank-pop)
      (define-key km "\C-c\C-d" 'bibtex-empty-field)
      (define-key km "\C-c\C-f" 'bibtex-make-field)
+     (define-key km "\C-c\C-u" 'bibtex-entry-update)
      (define-key km "\C-c$" 'bibtex-ispell-abstract)
      (define-key km "\M-\C-a" 'bibtex-beginning-of-entry)
      (define-key km "\M-\C-e" 'bibtex-end-of-entry)
***************
*** 1122,1165 ****
   '(bibtex-mode "@\\S(*\\s(" "\\s)" nil bibtex-hs-forward-sexp nil))
  
  
- (defconst bibtex-braced-string-syntax-table
-   (let ((st (make-syntax-table)))
-     (modify-syntax-entry ?\{ "(}" st)
-     (modify-syntax-entry ?\} "){" st)
-     (modify-syntax-entry ?\[ "." st)
-     (modify-syntax-entry ?\] "." st)
-     (modify-syntax-entry ?\( "." st)
-     (modify-syntax-entry ?\) "." st)
-     (modify-syntax-entry ?\\ "." st)
-     (modify-syntax-entry ?\" "." st)
-     st)
-   "Syntax-table to parse matched braces.")
- 
- (defconst bibtex-quoted-string-syntax-table
-   (let ((st (make-syntax-table)))
-     (modify-syntax-entry ?\\ "\\" st)
-     (modify-syntax-entry ?\" "\"" st)
-     st)
-   "Syntax-table to parse matched quotes.")
- 
- (defun bibtex-parse-field-string ()
-   "Parse a field string enclosed by braces or quotes.
- If a syntactically correct string is found, a pair containing the start and
- end position of the field string is returned, nil otherwise."
-   (let ((end-point
-          (or (and (eq (following-char) ?\")
-                   (save-excursion
-                     (with-syntax-table bibtex-quoted-string-syntax-table
-                       (forward-sexp 1))
-                     (point)))
-              (and (eq (following-char) ?\{)
-                   (save-excursion
-                     (with-syntax-table bibtex-braced-string-syntax-table
-                       (forward-sexp 1))
-                     (point))))))
-     (if end-point
-         (cons (point) end-point))))
- 
  (defun bibtex-parse-association (parse-lhs parse-rhs)
    "Parse a string of the format <left-hand-side = right-hand-side>.
  The functions PARSE-LHS and PARSE-RHS are used to parse the corresponding
--- 1124,1129 ----
***************
*** 1199,1204 ****
--- 1163,1206 ----
           ;; Now try again.
           (bibtex-parse-field-name))))
  
+ (defconst bibtex-braced-string-syntax-table
+   (let ((st (make-syntax-table)))
+     (modify-syntax-entry ?\{ "(}" st)
+     (modify-syntax-entry ?\} "){" st)
+     (modify-syntax-entry ?\[ "." st)
+     (modify-syntax-entry ?\] "." st)
+     (modify-syntax-entry ?\( "." st)
+     (modify-syntax-entry ?\) "." st)
+     (modify-syntax-entry ?\\ "." st)
+     (modify-syntax-entry ?\" "." st)
+     st)
+   "Syntax-table to parse matched braces.")
+ 
+ (defconst bibtex-quoted-string-syntax-table
+   (let ((st (make-syntax-table)))
+     (modify-syntax-entry ?\\ "\\" st)
+     (modify-syntax-entry ?\" "\"" st)
+     st)
+   "Syntax-table to parse matched quotes.")
+ 
+ (defun bibtex-parse-field-string ()
+   "Parse a field string enclosed by braces or quotes.
+ If a syntactically correct string is found, a pair containing the start and
+ end position of the field string is returned, nil otherwise."
+   (let ((end-point
+          (or (and (eq (following-char) ?\")
+                   (save-excursion
+                     (with-syntax-table bibtex-quoted-string-syntax-table
+                       (forward-sexp 1))
+                     (point)))
+              (and (eq (following-char) ?\{)
+                   (save-excursion
+                     (with-syntax-table bibtex-braced-string-syntax-table
+                       (forward-sexp 1))
+                     (point))))))
+     (if end-point
+         (cons (point) end-point))))
+ 
  (defun bibtex-parse-field-text ()
    "Parse the text part of a BibTeX field.
  The text part is either a string, or an empty string, or a constant followed
***************
*** 1410,1416 ****
    (let ((content (buffer-substring-no-properties (nth 0 (cdr bounds))
                                                   (nth 1 (cdr bounds)))))
      (if (and remove-delim
!              (string-match "\\`{\\(.*\\)}\\'" content))
          (substring content (match-beginning 1) (match-end 1))
        content)))
  
--- 1412,1418 ----
    (let ((content (buffer-substring-no-properties (nth 0 (cdr bounds))
                                                   (nth 1 (cdr bounds)))))
      (if (and remove-delim
!              (string-match "\\`[{\"]\\(.*\\)[}\"]\\'" content))
          (substring content (match-beginning 1) (match-end 1))
        content)))
  
***************
*** 1455,1470 ****
        (setq list (cdr list)))
      list))
  
- (defun bibtex-assoc-of-regexp (string alist)
-   "Return non-nil if STRING is exactly matched by the car of an
- element of ALIST (case ignored). The value is actually the element
- of LIST whose car matches STRING."
-   (let ((case-fold-search t))
-     (while (and alist
-                 (not (string-match (concat "\\`\\(?:" (caar alist) "\\)\\'") 
string)))
-       (setq alist (cdr alist)))
-     (car alist)))
- 
  (defun bibtex-skip-to-valid-entry (&optional backward)
    "Unless at beginning of a valid BibTeX entry, move point to beginning of the
  next valid one. With optional argument BACKWARD non-nil, move backward to
--- 1457,1462 ----
***************
*** 1510,1516 ****
          (save-excursion
            (if (or (and (not bibtex-sort-ignore-string-entries)
                         (string-equal "string" (downcase entry-type)))
!                   (assoc-ignore-case entry-type bibtex-entry-field-alist))
                (funcall fun key beg end)))
          (goto-char end)))))
  
--- 1502,1508 ----
          (save-excursion
            (if (or (and (not bibtex-sort-ignore-string-entries)
                         (string-equal "string" (downcase entry-type)))
!                   (assoc-string entry-type bibtex-entry-field-alist t))
                (funcall fun key beg end)))
          (goto-char end)))))
  
***************
*** 1519,1526 ****
  If FLAG is a string, the message is initialized (in this case a
  value for INTERVAL may be given as well (if not this is set to 5)).
  If FLAG is done, the message is deinitialized.
! If FLAG is absent, a message is echoed if point was incremented
! at least INTERVAL percent since last message was echoed."
    (cond ((stringp flag)
           (setq bibtex-progress-lastmes flag)
           (setq bibtex-progress-interval (or interval 5)
--- 1511,1518 ----
  If FLAG is a string, the message is initialized (in this case a
  value for INTERVAL may be given as well (if not this is set to 5)).
  If FLAG is done, the message is deinitialized.
! If FLAG is nil, a message is echoed if point was incremented at least
! `bibtex-progress-interval' percent since last message was echoed."
    (cond ((stringp flag)
           (setq bibtex-progress-lastmes flag)
           (setq bibtex-progress-interval (or interval 5)
***************
*** 1685,1695 ****
    "Try to avoid point being at end of a BibTeX field."
    (end-of-line)
    (skip-chars-backward " \t")
!   (cond ((= (preceding-char) ?,)
!          (forward-char -2)))
!   (cond ((or (= (preceding-char) ?})
!              (= (preceding-char) ?\"))
!          (forward-char -1))))
  
  (defun bibtex-enclosing-field (&optional noerr)
    "Search for BibTeX field enclosing point. Point moves to end of field.
--- 1677,1687 ----
    "Try to avoid point being at end of a BibTeX field."
    (end-of-line)
    (skip-chars-backward " \t")
!   (if (= (preceding-char) ?,)
!       (forward-char -2))
!   (if (or (= (preceding-char) ?})
!           (= (preceding-char) ?\"))
!       (forward-char -1)))
  
  (defun bibtex-enclosing-field (&optional noerr)
    "Search for BibTeX field enclosing point. Point moves to end of field.
***************
*** 1749,1754 ****
--- 1741,1755 ----
          (error "Unknown tag field: %s.  Please submit a bug report"
                 bibtex-last-kill-command))))))
  
+ (defun bibtex-assoc-regexp (regexp alist)
+   "Return non-nil if REGEXP matches the car of an element of ALIST.
+ The value is actually the element of ALIST matched by REGEXP.
+ Case is ignored if `case-fold-search' is non-nil in the current buffer."
+   (while (and alist
+               (not (string-match regexp (caar alist))))
+     (setq alist (cdr alist)))
+   (car alist))
+ 
  (defun bibtex-format-entry ()
    "Helper function for `bibtex-clean-entry'.
  Formats current entry according to variable `bibtex-entry-format'."
***************
*** 1763,1780 ****
                                    unify-case inherit-booktitle)
                        bibtex-entry-format))
              crossref-key bounds alternatives-there non-empty-alternative
!             entry-list req creq field-done field-list)
  
          ;; identify entry type
          (goto-char (point-min))
          (re-search-forward bibtex-entry-type)
          (let ((beg-type (1+ (match-beginning 0)))
                (end-type (match-end 0)))
!           (setq entry-list (assoc-ignore-case (buffer-substring-no-properties
!                                                beg-type end-type)
!                                               bibtex-entry-field-alist)
!                 req  (nth 0 (nth 1 entry-list))  ; required part
!                 creq (nth 0 (nth 2 entry-list))) ; crossref part
  
            ;; unify case of entry name
            (when (memq 'unify-case format)
--- 1764,1780 ----
                                    unify-case inherit-booktitle)
                        bibtex-entry-format))
              crossref-key bounds alternatives-there non-empty-alternative
!             entry-list req-field-list field-done field-list)
  
          ;; identify entry type
          (goto-char (point-min))
          (re-search-forward bibtex-entry-type)
          (let ((beg-type (1+ (match-beginning 0)))
                (end-type (match-end 0)))
!           (setq entry-list (assoc-string (buffer-substring-no-properties
!                                         beg-type end-type)
!                                        bibtex-entry-field-alist
!                                        t))
  
            ;; unify case of entry name
            (when (memq 'unify-case format)
***************
*** 1791,1810 ****
          ;; determine if entry has crossref field and if at least
          ;; one alternative is non-empty
          (goto-char (point-min))
!         (while (setq bounds (bibtex-search-forward-field
!                              bibtex-field-name))
!           (goto-char (bibtex-start-of-name-in-field bounds))
!           (cond ((looking-at "ALT")
!                  (setq alternatives-there t)
!                  (goto-char (bibtex-start-of-text-in-field bounds))
!                  (if (not (looking-at bibtex-empty-field-re))
!                      (setq non-empty-alternative t)))
!                 ((and (looking-at "\\(OPT\\)?crossref\\>")
!                       (progn (goto-char (bibtex-start-of-text-in-field 
bounds))
!                              (not (looking-at bibtex-empty-field-re))))
!                  (setq crossref-key
!                        (bibtex-text-in-field-bounds bounds t))))
!           (goto-char (bibtex-end-of-field bounds)))
          (if (and alternatives-there
                   (not non-empty-alternative)
                   (memq 'required-fields format))
--- 1791,1822 ----
          ;; determine if entry has crossref field and if at least
          ;; one alternative is non-empty
          (goto-char (point-min))
!         (let* ((fields-alist (bibtex-parse-entry))
!                (case-fold-search t)
!                (field (bibtex-assoc-regexp "\\`\\(OPT\\)?crossref\\'"
!                                            fields-alist)))
!           (setq crossref-key (and field
!                                   (not (string-match bibtex-empty-field-re
!                                                      (cdr field)))
!                                   (cdr field))
!                 req-field-list (if crossref-key
!                                    (nth 0 (nth 2 entry-list))  ; crossref part
!                                  (nth 0 (nth 1 entry-list))))  ; required part
! 
!           (dolist (rfield req-field-list)
!             (when (nth 3 rfield) ; we should have an alternative
!               (setq alternatives-there t
!                     field (bibtex-assoc-regexp
!                            (concat "\\`\\(ALT\\)?" (car rfield) "\\'")
!                            fields-alist))
!               (if (and field
!                        (not (string-match bibtex-empty-field-re
!                                           (cdr field))))
!                   (cond ((not non-empty-alternative)
!                          (setq non-empty-alternative t))
!                         ((memq 'required-fields format)
!                          (error "More than one non-empty alternative.")))))))
! 
          (if (and alternatives-there
                   (not non-empty-alternative)
                   (memq 'required-fields format))
***************
*** 1832,1849 ****
              ;; quite some redundancy compared with what we need to do
              ;; anyway. So for speed-up we avoid using them.
  
!             (when (and opt-alt
!                        (memq 'opts-or-alts format))
!               (if empty-field
!                   ;; Either it is an empty ALT field. Then we have checked
!                   ;; already that we have one non-empty alternative.
!                   ;; Or it is an empty OPT field that we do not miss anyway.
!                   ;; So we can safely delete this field.
!                   (progn (delete-region beg-field end-field)
!                          (setq deleted t))
!                 ;; otherwise: not empty, delete "OPT" or "ALT"
!                 (goto-char beg-name)
!                 (delete-char 3)))
  
              (unless deleted
                (push field-name field-list)
--- 1844,1866 ----
              ;; quite some redundancy compared with what we need to do
              ;; anyway. So for speed-up we avoid using them.
  
!             (if (memq 'opts-or-alts format)
!                 (cond ((and empty-field
!                             (or opt-alt
!                                 (let ((field (assoc-string
!                                               field-name req-field-list t)))
!                                   (or (not field)       ; OPT field
!                                       (nth 3 field))))) ; ALT field
!                        ;; Either it is an empty ALT field. Then we have 
checked
!                        ;; already that we have one non-empty alternative. Or 
it
!                        ;; is an empty OPT field that we do not miss anyway.
!                        ;; So we can safely delete this field.
!                        (delete-region beg-field end-field)
!                        (setq deleted t))
!                       ;; otherwise: not empty, delete "OPT" or "ALT"
!                       (opt-alt
!                        (goto-char beg-name)
!                        (delete-char 3))))
  
              (unless deleted
                (push field-name field-list)
***************
*** 1902,1917 ****
                ;; if empty field, complain
                (if (and empty-field
                         (memq 'required-fields format)
!                        (assoc-ignore-case field-name
!                                           (if crossref-key creq req)))
                    (error "Mandatory field `%s' is empty" field-name))
  
                ;; unify case of field name
                (if (memq 'unify-case format)
!                   (let ((fname (car (assoc-ignore-case
!                                      field-name (append (nth 0 (nth 1 
entry-list))
!                                                         (nth 1 (nth 1 
entry-list))
!                                                         
bibtex-user-optional-fields)))))
                      (if fname
                          (progn
                            (delete-region beg-name end-name)
--- 1919,1935 ----
                ;; if empty field, complain
                (if (and empty-field
                         (memq 'required-fields format)
!                        (assoc-string field-name req-field-list t))
                    (error "Mandatory field `%s' is empty" field-name))
  
                ;; unify case of field name
                (if (memq 'unify-case format)
!                   (let ((fname (car (assoc-string
!                                      field-name
!                                    (append (nth 0 (nth 1 entry-list))
!                                            (nth 1 (nth 1 entry-list))
!                                            bibtex-user-optional-fields)
!                                    t))))
                      (if fname
                          (progn
                            (delete-region beg-name end-name)
***************
*** 1925,1932 ****
  
          ;; check whether all required fields are present
          (if (memq 'required-fields format)
!             (let (altlist (found 0))
!               (dolist (fname (if crossref-key creq req))
                  (if (nth 3 fname)
                      (push (car fname) altlist))
                  (unless (or (member (car fname) field-list)
--- 1943,1950 ----
  
          ;; check whether all required fields are present
          (if (memq 'required-fields format)
!             (let ((found 0) altlist)
!               (dolist (fname req-field-list)
                  (if (nth 3 fname)
                      (push (car fname) altlist))
                  (unless (or (member (car fname) field-list)
***************
*** 1940,1946 ****
                         (error "Alternative mandatory field `%s' is missing"
                                altlist))
                        ((> found 1)
!                        (error "Alternative fields `%s' is defined %s times"
                                altlist found))))))
  
          ;; update point
--- 1958,1964 ----
                         (error "Alternative mandatory field `%s' is missing"
                                altlist))
                        ((> found 1)
!                        (error "Alternative fields `%s' are defined %s times"
                                altlist found))))))
  
          ;; update point
***************
*** 2051,2058 ****
              (setq titlestring (substring titlestring 0 (match-beginning 
0))))))
      ;; gather words from titlestring into a list. Ignore
      ;; specific words and use only a specific amount of words.
!     (let (case-fold-search titlewords titlewords-extra titleword end-match
!                            (counter 0))
        (while (and (or (not (numberp bibtex-autokey-titlewords))
                        (< counter (+ bibtex-autokey-titlewords
                                      bibtex-autokey-titlewords-stretch)))
--- 2069,2076 ----
              (setq titlestring (substring titlestring 0 (match-beginning 
0))))))
      ;; gather words from titlestring into a list. Ignore
      ;; specific words and use only a specific amount of words.
!     (let ((counter 0)
!           case-fold-search titlewords titlewords-extra titleword end-match)
        (while (and (or (not (numberp bibtex-autokey-titlewords))
                        (< counter (+ bibtex-autokey-titlewords
                                      bibtex-autokey-titlewords-stretch)))
***************
*** 2079,2088 ****
    "Do some abbreviations on TITLEWORD.
  The rules are defined in `bibtex-autokey-titleword-abbrevs'
  and `bibtex-autokey-titleword-length'."
!   (let ((abbrev (bibtex-assoc-of-regexp
!                  titleword bibtex-autokey-titleword-abbrevs)))
!     (if abbrev
!         (cdr abbrev)
        (bibtex-autokey-abbrev titleword
                               bibtex-autokey-titleword-length))))
  
--- 2097,2110 ----
    "Do some abbreviations on TITLEWORD.
  The rules are defined in `bibtex-autokey-titleword-abbrevs'
  and `bibtex-autokey-titleword-length'."
!   (let ((case-folde-search t)
!         (alist bibtex-autokey-titleword-abbrevs))
!     (while (and alist
!                 (not (string-match (concat "\\`\\(?:" (caar alist) "\\)\\'")
!                                    titleword)))
!       (setq alist (cdr alist)))
!     (if alist
!         (cdar alist)
        (bibtex-autokey-abbrev titleword
                               bibtex-autokey-titleword-length))))
  
***************
*** 2239,2246 ****
                                      ;; This is a crossref.
                                      (buffer-substring-no-properties
                                       (1+ (match-beginning 3)) (1- (match-end 
3))))
!                                    ((assoc-ignore-case (bibtex-type-in-head)
!                                                        
bibtex-entry-field-alist)
                                      ;; This is an entry.
                                      (match-string-no-properties 
bibtex-key-in-head)))))
                      (if (and (stringp key)
--- 2261,2268 ----
                                      ;; This is a crossref.
                                      (buffer-substring-no-properties
                                       (1+ (match-beginning 3)) (1- (match-end 
3))))
!                                    ((assoc-string (bibtex-type-in-head)
!                                                 bibtex-entry-field-alist t)
                                      ;; This is an entry.
                                      (match-string-no-properties 
bibtex-key-in-head)))))
                      (if (and (stringp key)
***************
*** 2295,2301 ****
                  ;; user has aborted by typing a key --> return `aborted'
                  (throw 'userkey 'aborted))
              (setq key (bibtex-reference-key-in-string bounds))
!             (if (not (assoc-ignore-case key strings))
                  (push (cons key (bibtex-text-in-string bounds t))
                        strings))
              (goto-char (bibtex-end-of-text-in-string bounds)))
--- 2317,2323 ----
                  ;; user has aborted by typing a key --> return `aborted'
                  (throw 'userkey 'aborted))
              (setq key (bibtex-reference-key-in-string bounds))
!             (if (not (assoc key strings))
                  (push (cons key (bibtex-text-in-string bounds t))
                        strings))
              (goto-char (bibtex-end-of-text-in-string bounds)))
***************
*** 2384,2389 ****
--- 2406,2412 ----
               (display-completion-list (all-completions part-of-word
                                                         completions)))
             (message "Making completion list...done")
+            ;; return value is handled by choose-completion-string-functions
             nil))))
  
  (defun bibtex-complete-string-cleanup (str)
***************
*** 2629,2634 ****
--- 2652,2685 ----
    (easy-menu-add bibtex-entry-menu)
    (run-hooks 'bibtex-mode-hook))
  
+ (defun bibtex-field-list (entry-type)
+   "Return list of allowed fields for entry ENTRY-TYPE.
+ More specifically, the return value is a cons pair (REQUIRED . OPTIONAL),
+ where REQUIRED and OPTIONAL are lists of the required and optional field
+ names for ENTRY-TYPE according to `bibtex-entry-field-alist'."
+   (let ((e (assoc-string entry-type bibtex-entry-field-alist t))
+         required optional)
+     (unless e
+       (error "Bibtex entry type %s not defined" entry-type))
+     (if (and (member-ignore-case entry-type bibtex-include-OPTcrossref)
+              (nth 2 e))
+         (setq required (nth 0 (nth 2 e))
+               optional (nth 1 (nth 2 e)))
+       (setq required (nth 0 (nth 1 e))
+             optional (nth 1 (nth 1 e))))
+     (if bibtex-include-OPTkey
+         (push (list "key"
+                     "Used for reference key creation if author and editor 
fields are missing"
+                     (if (or (stringp bibtex-include-OPTkey)
+                             (fboundp bibtex-include-OPTkey))
+                         bibtex-include-OPTkey))
+               optional))
+     (if (member-ignore-case entry-type bibtex-include-OPTcrossref)
+         (push '("crossref" "Reference key of the cross-referenced entry")
+               optional))
+     (setq optional (append optional bibtex-user-optional-fields))
+     (cons required optional)))
+ 
  (defun bibtex-entry (entry-type)
    "Insert a new BibTeX entry.
  After insertion it calls the functions in `bibtex-add-entry-hook'."
***************
*** 2638,2675 ****
                              bibtex-entry-field-alist
                              nil t nil 'bibtex-entry-type-history)))
                   (list e-t)))
!   (let* (required optional
!          (key (if bibtex-maintain-sorted-entries
!                   (bibtex-read-key (format "%s key: " entry-type))))
!          (e (assoc-ignore-case entry-type bibtex-entry-field-alist))
!          (r-n-o (elt e 1))
!          (c-ref (elt e 2)))
!     (if (not e)
!         (error "Bibtex entry type %s not defined" entry-type))
!     (if (and (member entry-type bibtex-include-OPTcrossref)
!              c-ref)
!         (setq required (elt c-ref 0)
!               optional (elt c-ref 1))
!       (setq required (elt r-n-o 0)
!             optional (elt r-n-o 1)))
      (unless (bibtex-prepare-new-entry (list key nil entry-type))
        (error "Entry with key `%s' already exists" key))
      (indent-to-column bibtex-entry-offset)
      (insert "@" entry-type (bibtex-entry-left-delimiter))
!     (if key
!         (insert key))
      (save-excursion
!       (mapcar 'bibtex-make-field required)
!       (if (member entry-type bibtex-include-OPTcrossref)
!           (bibtex-make-optional-field '("crossref")))
!       (if bibtex-include-OPTkey
!           (if (or (stringp bibtex-include-OPTkey)
!                   (fboundp bibtex-include-OPTkey))
!               (bibtex-make-optional-field
!                (list "key" nil bibtex-include-OPTkey))
!             (bibtex-make-optional-field '("key"))))
!       (mapcar 'bibtex-make-optional-field optional)
!       (mapcar 'bibtex-make-optional-field bibtex-user-optional-fields)
        (if bibtex-comma-after-last-field
            (insert ","))
        (insert "\n")
--- 2689,2705 ----
                              bibtex-entry-field-alist
                              nil t nil 'bibtex-entry-type-history)))
                   (list e-t)))
!   (let ((key (if bibtex-maintain-sorted-entries
!                  (bibtex-read-key (format "%s key: " entry-type))))
!         (field-list (bibtex-field-list entry-type)))
      (unless (bibtex-prepare-new-entry (list key nil entry-type))
        (error "Entry with key `%s' already exists" key))
      (indent-to-column bibtex-entry-offset)
      (insert "@" entry-type (bibtex-entry-left-delimiter))
!     (if key (insert key))
      (save-excursion
!       (mapcar 'bibtex-make-field (car field-list))
!       (mapcar 'bibtex-make-optional-field (cdr field-list))
        (if bibtex-comma-after-last-field
            (insert ","))
        (insert "\n")
***************
*** 2680,2694 ****
        (bibtex-autofill-entry))
      (run-hooks 'bibtex-add-entry-hook)))
  
  (defun bibtex-parse-entry ()
    "Parse entry at point, return an alist.
  The alist elements have the form (FIELD . TEXT), where FIELD can also be
! the special strings \"=type=\" and \"=key=\"."
    (let (alist bounds)
!     (when (looking-at bibtex-entry-head)
        (push (cons "=type=" (match-string bibtex-type-in-head)) alist)
        (push (cons "=key=" (match-string bibtex-key-in-head)) alist)
!       (goto-char (match-end bibtex-key-in-head))
        (while (setq bounds (bibtex-parse-field bibtex-field-name))
        (push (cons (bibtex-name-in-field bounds)
                    (bibtex-text-in-field-bounds bounds))
--- 2710,2748 ----
        (bibtex-autofill-entry))
      (run-hooks 'bibtex-add-entry-hook)))
  
+ (defun bibtex-entry-update ()
+   "Update an existing BibTeX entry.
+ In the BibTeX entry at point, make new fields for those items that may occur
+ according to `bibtex-entry-field-alist', but are not yet present."
+   (interactive)
+   (save-excursion
+     (bibtex-beginning-of-entry)
+     ;; For inserting new fields, we use the fact that
+     ;; bibtex-parse-entry moves point to the end of the last field.
+     (let* ((fields-alist (bibtex-parse-entry))
+            (field-list (bibtex-field-list
+                         (substring (cdr (assoc "=type=" fields-alist))
+                                    1))) ; don't want @
+            (case-fold-search t))
+       (dolist (field (car field-list))
+         (unless (bibtex-assoc-regexp (concat "\\`\\(ALT\\)?" (car field) 
"\\'")
+                                      fields-alist)
+           (bibtex-make-field field)))
+       (dolist (field (cdr field-list))
+         (unless (bibtex-assoc-regexp (concat "\\`\\(OPT\\)?" (car field) 
"\\'")
+                                      fields-alist)
+           (bibtex-make-optional-field field))))))
+ 
  (defun bibtex-parse-entry ()
    "Parse entry at point, return an alist.
  The alist elements have the form (FIELD . TEXT), where FIELD can also be
! the special strings \"=type=\" and \"=key=\". For the FIELD \"=key=\"
! TEXT may be nil. Move point to the end of the last field."
    (let (alist bounds)
!     (when (looking-at bibtex-entry-maybe-empty-head)
        (push (cons "=type=" (match-string bibtex-type-in-head)) alist)
        (push (cons "=key=" (match-string bibtex-key-in-head)) alist)
!       (goto-char (match-end 0))
        (while (setq bounds (bibtex-parse-field bibtex-field-name))
        (push (cons (bibtex-name-in-field bounds)
                    (bibtex-text-in-field-bounds bounds))
***************
*** 2744,2750 ****
          (let* ((name (buffer-substring
                        (if (looking-at "ALT\\|OPT") (match-end 0) (point))
                        (bibtex-end-of-name-in-field bounds)))
!                (text (assoc-ignore-case name other)))
            (goto-char (bibtex-start-of-text-in-field bounds))
            (if (not (and (looking-at bibtex-empty-field-re) text))
                (goto-char (bibtex-end-of-field bounds))
--- 2798,2804 ----
          (let* ((name (buffer-substring
                        (if (looking-at "ALT\\|OPT") (match-end 0) (point))
                        (bibtex-end-of-name-in-field bounds)))
!                (text (assoc-string name other t)))
            (goto-char (bibtex-start-of-text-in-field bounds))
            (if (not (and (looking-at bibtex-empty-field-re) text))
                (goto-char (bibtex-end-of-field bounds))
***************
*** 2774,2801 ****
                                     (looking-at "OPT\\|ALT"))
                              (match-end 0) mb)
                          (bibtex-end-of-name-in-field bounds)))
!            (entry-type (progn (re-search-backward
!                                bibtex-entry-maybe-empty-head nil t)
!                               (bibtex-type-in-head)))
!            (entry-list (assoc-ignore-case entry-type
!                                           bibtex-entry-field-alist))
!            (c-r-list (elt entry-list 2))
!            (req-opt-list (if (and (member entry-type
!                                           bibtex-include-OPTcrossref)
!                                   c-r-list)
!                              c-r-list
!                            (elt entry-list 1)))
!            (list-of-entries (append (elt req-opt-list 0)
!                                     (elt req-opt-list 1)
!                                     bibtex-user-optional-fields
!                                     (if (member entry-type
!                                                 bibtex-include-OPTcrossref)
!                                         '(("crossref" "Reference key of the 
cross-referenced entry")))
!                                     (if bibtex-include-OPTkey
!                                         '(("key" "Used for reference key 
creation if author and editor fields are missing")))))
!            (comment (assoc-ignore-case field-name list-of-entries)))
        (if comment
!           (message (elt comment 1))
          (message "No comment available")))))
  
  (defun bibtex-make-field (field &optional called-by-yank)
--- 2828,2842 ----
                                     (looking-at "OPT\\|ALT"))
                              (match-end 0) mb)
                          (bibtex-end-of-name-in-field bounds)))
!            (field-list (bibtex-field-list (progn (re-search-backward
!                                                   
bibtex-entry-maybe-empty-head nil t)
!                                                  (bibtex-type-in-head))))
!            (comment (assoc-string field-name
!                                 (append (car field-list)
!                                         (cdr field-list))
!                                 t)))
        (if comment
!           (message (nth 1 comment))
          (message "No comment available")))))
  
  (defun bibtex-make-field (field &optional called-by-yank)
***************
*** 2804,2827 ****
  \(FIELD-NAME COMMENT-STRING INIT ALTERNATIVE-FLAG) as in
  `bibtex-entry-field-alist'."
    (interactive
!    (list (let* ((entry-type
!                  (save-excursion
!                    (bibtex-enclosing-entry-maybe-empty-head)
!                    (bibtex-type-in-head)))
!                 ;; "preliminary" completion list
!                 (fl (nth 1 (assoc-ignore-case
!                             entry-type bibtex-entry-field-alist)))
!                 ;; "full" completion list
!                 (field-list (append (nth 0 fl)
!                                     (nth 1 fl)
!                                     bibtex-user-optional-fields
!                                     (if (member entry-type
!                                                 bibtex-include-OPTcrossref)
!                                         '(("crossref")))
!                                     (if bibtex-include-OPTkey
!                                         '(("key")))))
!                 (completion-ignore-case t))
!            (completing-read "BibTeX field name: " field-list
                              nil nil nil bibtex-field-history))))
    (unless (consp field)
      (setq field (list field)))
--- 2845,2857 ----
  \(FIELD-NAME COMMENT-STRING INIT ALTERNATIVE-FLAG) as in
  `bibtex-entry-field-alist'."
    (interactive
!    (list (let ((completion-ignore-case t)
!                (field-list (bibtex-field-list
!                              (save-excursion
!                                (bibtex-enclosing-entry-maybe-empty-head)
!                                (bibtex-type-in-head)))))
!            (completing-read "BibTeX field name: "
!                             (append (car field-list) (cdr field-list))
                              nil nil nil bibtex-field-history))))
    (unless (consp field)
      (setq field (list field)))
***************
*** 2848,2855 ****
            ((fboundp init)
             (insert (funcall init)))))
    (if (not called-by-yank) (insert (bibtex-field-right-delimiter)))
!   (if (interactive-p)
!       (forward-char -1)))
  
  (defun bibtex-beginning-of-entry ()
    "Move to beginning of BibTeX entry (beginning of line).
--- 2878,2886 ----
            ((fboundp init)
             (insert (funcall init)))))
    (if (not called-by-yank) (insert (bibtex-field-right-delimiter)))
!   (when (interactive-p)
!     (forward-char -1)
!     (bibtex-print-help-message)))
  
  (defun bibtex-beginning-of-entry ()
    "Move to beginning of BibTeX entry (beginning of line).
***************
*** 2982,2994 ****
                                 "\\(OPT\\)?crossref" t)))
                    (list key
                          (if bounds (bibtex-text-in-field-bounds bounds t))
!                         entry-name))))
!           (list key nil entry-name)))))
  
  (defun bibtex-lessp (index1 index2)
    "Predicate for sorting BibTeX entries with indices INDEX1 and INDEX2.
  Each index is a list (KEY CROSSREF-KEY ENTRY-NAME).
! The predicate depends on the variable `bibtex-maintain-sorted-entries'."
    (cond ((not index1) (not index2)) ; indices can be nil
          ((not index2) nil)
          ((equal bibtex-maintain-sorted-entries 'crossref)
--- 3013,3026 ----
                                 "\\(OPT\\)?crossref" t)))
                    (list key
                          (if bounds (bibtex-text-in-field-bounds bounds t))
!                         entry-name)))
!             (list key nil entry-name))))))
  
  (defun bibtex-lessp (index1 index2)
    "Predicate for sorting BibTeX entries with indices INDEX1 and INDEX2.
  Each index is a list (KEY CROSSREF-KEY ENTRY-NAME).
! The predicate depends on the variable `bibtex-maintain-sorted-entries'.
! If its value is nil use plain sorting."
    (cond ((not index1) (not index2)) ; indices can be nil
          ((not index2) nil)
          ((equal bibtex-maintain-sorted-entries 'crossref)
***************
*** 3017,3028 ****
  (defun bibtex-sort-buffer ()
    "Sort BibTeX buffer alphabetically by key.
  The predicate for sorting is defined via `bibtex-maintain-sorted-entries'.
! Text outside of BibTeX entries is not affected.  If
! `bibtex-sort-ignore-string-entries' is non-nil, @String entries will be
! ignored."
    (interactive)
-   (unless bibtex-maintain-sorted-entries
-     (error "You must choose a sorting scheme"))
    (save-restriction
      (narrow-to-region (bibtex-beginning-of-first-entry)
                        (save-excursion (goto-char (point-max))
--- 3049,3058 ----
  (defun bibtex-sort-buffer ()
    "Sort BibTeX buffer alphabetically by key.
  The predicate for sorting is defined via `bibtex-maintain-sorted-entries'.
! If its value is nil use plain sorting. Text outside of BibTeX entries is not
! affected. If `bibtex-sort-ignore-string-entries' is non-nil, @String entries
! will be ignored."
    (interactive)
    (save-restriction
      (narrow-to-region (bibtex-beginning-of-first-entry)
                        (save-excursion (goto-char (point-max))
***************
*** 3212,3219 ****
                   (let* ((entry-list (progn
                                        (goto-char beg)
                                        (bibtex-search-entry nil end)
!                                       (assoc-ignore-case (bibtex-type-in-head)
!                                                          
bibtex-entry-field-alist)))
                          (req (copy-sequence (elt (elt entry-list 1) 0)))
                          (creq (copy-sequence (elt (elt entry-list 2) 0)))
                          crossref-there bounds)
--- 3242,3249 ----
                   (let* ((entry-list (progn
                                        (goto-char beg)
                                        (bibtex-search-entry nil end)
!                                       (assoc-string (bibtex-type-in-head)
!                                                   bibtex-entry-field-alist 
t)))
                          (req (copy-sequence (elt (elt entry-list 1) 0)))
                          (creq (copy-sequence (elt (elt entry-list 2) 0)))
                          crossref-there bounds)
***************
*** 3229,3236 ****
                             (push (list (bibtex-current-line)
                                         "Questionable month field")
                                   error-list))
!                        (setq req (delete (assoc-ignore-case field-name req) 
req)
!                              creq (delete (assoc-ignore-case field-name creq) 
creq))
                         (if (equal field-name "crossref")
                             (setq crossref-there t))))
                     (if crossref-there
--- 3259,3266 ----
                             (push (list (bibtex-current-line)
                                         "Questionable month field")
                                   error-list))
!                        (setq req (delete (assoc-string field-name req t) req)
!                              creq (delete (assoc-string field-name creq t) 
creq))
                         (if (equal field-name "crossref")
                             (setq crossref-there t))))
                     (if crossref-there
***************
*** 3523,3549 ****
                           (match-end bibtex-key-in-head)))
        (insert key))
      ;; sorting
!     (let* ((start (bibtex-beginning-of-entry))
!            (end (progn (bibtex-end-of-entry)
!                        (if (re-search-forward
!                             bibtex-entry-maybe-empty-head nil 'move)
!                            (goto-char (match-beginning 0)))
!                        (point)))
!            (entry (buffer-substring start end))
!            (index (progn (goto-char start)
!                          (bibtex-entry-index))))
!       (delete-region start end)
!       (unless (prog1 (or called-by-reformat
!                          (if (and bibtex-maintain-sorted-entries
!                                   (not (and bibtex-sort-ignore-string-entries
!                                             (equal entry-type "string"))))
!                              (bibtex-prepare-new-entry index)
!                            (not (bibtex-find-entry (car index)))))
!                 (insert entry)
!                 (forward-char -1)
!                 (bibtex-beginning-of-entry) ; moves backward
!                 (re-search-forward bibtex-entry-head))
!         (error "New inserted entry yields duplicate key")))
      ;; final clean up
      (unless called-by-reformat
        (save-excursion
--- 3553,3582 ----
                           (match-end bibtex-key-in-head)))
        (insert key))
      ;; sorting
!     (unless called-by-reformat
!       (let* ((start (bibtex-beginning-of-entry))
!              (end (progn (bibtex-end-of-entry)
!                          (if (re-search-forward
!                               bibtex-entry-maybe-empty-head nil 'move)
!                              (goto-char (match-beginning 0)))
!                          (point)))
!              (entry (buffer-substring start end))
!              (index (progn (goto-char start)
!                            (bibtex-entry-index)))
!              no-error)
!         (if (and bibtex-maintain-sorted-entries
!                  (not (and bibtex-sort-ignore-string-entries
!                            (equal entry-type "string"))))
!             (progn
!               (delete-region start end)
!               (setq no-error (bibtex-prepare-new-entry index))
!               (insert entry)
!               (forward-char -1)
!               (bibtex-beginning-of-entry) ; moves backward
!               (re-search-forward bibtex-entry-head))
!           (setq no-error (bibtex-find-entry (car index))))
!         (unless no-error
!           (error "New inserted entry yields duplicate key"))))
      ;; final clean up
      (unless called-by-reformat
        (save-excursion
***************
*** 3621,3711 ****
      (indent-to-column bibtex-entry-offset)
      (goto-char pnt)))
  
! (defun bibtex-reformat (&optional additional-options called-by-convert-alien)
    "Reformat all BibTeX entries in buffer or region.
  With prefix argument, read options for reformatting from minibuffer.
  With \\[universal-argument] \\[universal-argument] prefix argument, reuse 
previous answers (if any) again.
! If mark is active it reformats entries in region, if not in whole buffer."
    (interactive "*P")
    (let* ((pnt (point))
           (use-previous-options
!           (and (equal (prefix-numeric-value additional-options) 16)
                 (or bibtex-reformat-previous-options
                     bibtex-reformat-previous-reference-keys)))
           (bibtex-entry-format
!           (if additional-options
                (if use-previous-options
                    bibtex-reformat-previous-options
                  (setq bibtex-reformat-previous-options
!                       (delq nil (list
!                                  (if (or called-by-convert-alien
!                                          (y-or-n-p "Realign entries 
(recommended)? "))
!                                      'realign)
!                                  (if (y-or-n-p "Remove empty optional and 
alternative fields? ")
!                                      'opts-or-alts)
!                                  (if (y-or-n-p "Remove delimiters around pure 
numerical fields? ")
!                                      'numerical-fields)
!                                  (if (y-or-n-p (concat (if 
bibtex-comma-after-last-field "Insert" "Remove")
!                                                        " comma at end of 
entry? "))
!                                      'last-comma)
!                                  (if (y-or-n-p "Replace double page dashes by 
single ones? ")
!                                      'page-dashes)
!                                  (if (y-or-n-p "Force delimiters? ")
!                                      'delimiters)
!                                  (if (y-or-n-p "Unify case of entry types and 
field names? ")
!                                      'unify-case)))))
              '(realign)))
!          (reformat-reference-keys (if additional-options
!                                       (if use-previous-options
!                                           
bibtex-reformat-previous-reference-keys
!                                         (setq 
bibtex-reformat-previous-reference-keys
!                                               (y-or-n-p "Generate new 
reference keys automatically? ")))))
!          bibtex-autokey-edit-before-use
!          (bibtex-sort-ignore-string-entries t)
           (start-point (if (bibtex-mark-active)
                            (region-beginning)
!                         (bibtex-beginning-of-first-entry)
!                         (bibtex-skip-to-valid-entry)
!                         (point)))
           (end-point (if (bibtex-mark-active)
                          (region-end)
!                       (point-max))))
      (save-restriction
        (narrow-to-region start-point end-point)
!       (when (memq 'realign bibtex-entry-format)
!         (goto-char (point-min))
!         (while (re-search-forward bibtex-valid-entry-whitespace-re nil t)
!           (replace-match "\n\\1")))
        (goto-char start-point)
        (bibtex-progress-message "Formatting" 1)
        (bibtex-map-entries (lambda (key beg end)
                              (bibtex-progress-message)
!                             (bibtex-clean-entry reformat-reference-keys t)
!                             (when (memq 'realign bibtex-entry-format)
!                               (goto-char end)
!                               (bibtex-delete-whitespace)
!                               (open-line 2))))
        (bibtex-progress-message 'done))
      (when (and reformat-reference-keys
!                bibtex-maintain-sorted-entries
!                (not called-by-convert-alien))
        (bibtex-sort-buffer)
!       (kill-local-variable 'bibtex-reference-keys))
      (goto-char pnt)))
  
! (defun bibtex-convert-alien (&optional do-additional-reformatting)
    "Convert an alien BibTeX buffer to be fully usable by BibTeX mode.
! If a file does not conform with some standards used by BibTeX mode,
  some of the high-level features of BibTeX mode will not be available.
  This function tries to convert current buffer to conform with these standards.
! With prefix argument DO-ADDITIONAL-REFORMATTING
! non-nil, read options for reformatting entries from minibuffer."
    (interactive "*P")
    (message "Starting to validate buffer...")
    (sit-for 1 nil t)
!   (goto-char (point-min))
!   (while (re-search-forward "[ \t\n]+@" nil t)
!     (replace-match "\n@"))
    (message
     "If errors occur, correct them and call `bibtex-convert-alien' again")
    (sit-for 5 nil t)
--- 3654,3742 ----
      (indent-to-column bibtex-entry-offset)
      (goto-char pnt)))
  
! (defun bibtex-realign ()
!   "Realign BibTeX entries such that they are separated by one blank line."
!   (goto-char (point-min))
!   (let ((case-fold-search t))
!     (when (looking-at bibtex-valid-entry-whitespace-re)
!       (replace-match "\\1"))
!     (while (re-search-forward bibtex-valid-entry-whitespace-re nil t)
!       (replace-match "\n\n\\1"))))
! 
! (defun bibtex-reformat (&optional read-options)
    "Reformat all BibTeX entries in buffer or region.
  With prefix argument, read options for reformatting from minibuffer.
  With \\[universal-argument] \\[universal-argument] prefix argument, reuse 
previous answers (if any) again.
! If mark is active reformat entries in region, if not in whole buffer."
    (interactive "*P")
    (let* ((pnt (point))
           (use-previous-options
!           (and (equal (prefix-numeric-value read-options) 16)
                 (or bibtex-reformat-previous-options
                     bibtex-reformat-previous-reference-keys)))
           (bibtex-entry-format
!           (if read-options
                (if use-previous-options
                    bibtex-reformat-previous-options
                  (setq bibtex-reformat-previous-options
!                       (mapcar (lambda (option)
!                                 (if (y-or-n-p (car option)) (cdr option)))
!                               `(("Realign entries (recommended)? " . 'realign)
!                                 ("Remove empty optional and alternative 
fields? " . 'opts-or-alts)
!                                 ("Remove delimiters around pure numerical 
fields? " . 'numerical-fields)
!                                 (,(concat (if bibtex-comma-after-last-field 
"Insert" "Remove")
!                                          " comma at end of entry? ") . 
'last-comma)
!                                 ("Replace double page dashes by single ones? 
" . 'page-dashes)
!                                 ("Force delimiters? " . 'delimiters)
!                                 ("Unify case of entry types and field names? 
" . 'unify-case)))))
              '(realign)))
!          (reformat-reference-keys
!           (if read-options
!               (if use-previous-options
!                   bibtex-reformat-previous-reference-keys
!                 (setq bibtex-reformat-previous-reference-keys
!                       (y-or-n-p "Generate new reference keys automatically? 
")))))
           (start-point (if (bibtex-mark-active)
                            (region-beginning)
!                         (point-min)))
           (end-point (if (bibtex-mark-active)
                          (region-end)
!                       (point-max)))
!          (bibtex-sort-ignore-string-entries t)
!          bibtex-autokey-edit-before-use)
! 
      (save-restriction
        (narrow-to-region start-point end-point)
!       (if (memq 'realign bibtex-entry-format)
!         (bibtex-realign))
        (goto-char start-point)
        (bibtex-progress-message "Formatting" 1)
        (bibtex-map-entries (lambda (key beg end)
                              (bibtex-progress-message)
!                             (bibtex-clean-entry reformat-reference-keys t)))
!       (when (memq 'realign bibtex-entry-format)
!         (bibtex-delete-whitespace)
!         (open-line (if (eobp) 1 2)))
        (bibtex-progress-message 'done))
      (when (and reformat-reference-keys
!                bibtex-maintain-sorted-entries)
!       (bibtex-progress-message "Sorting" 1)
        (bibtex-sort-buffer)
!       (kill-local-variable 'bibtex-reference-keys)
!       (bibtex-progress-message 'done))
      (goto-char pnt)))
  
! (defun bibtex-convert-alien (&optional read-options)
    "Convert an alien BibTeX buffer to be fully usable by BibTeX mode.
! If a file does not conform with all standards used by BibTeX mode,
  some of the high-level features of BibTeX mode will not be available.
  This function tries to convert current buffer to conform with these standards.
! With prefix argument READ-OPTIONS non-nil, read options for reformatting
! entries from minibuffer."
    (interactive "*P")
    (message "Starting to validate buffer...")
    (sit-for 1 nil t)
!   (bibtex-realign)
    (message
     "If errors occur, correct them and call `bibtex-convert-alien' again")
    (sit-for 5 nil t)
***************
*** 3714,3723 ****
            (bibtex-validate))
      (message "Starting to reformat entries...")
      (sit-for 2 nil t)
!     (bibtex-reformat do-additional-reformatting t)
!     (when bibtex-maintain-sorted-entries
!       (message "Starting to sort buffer...")
!       (bibtex-sort-buffer))
      (goto-char (point-max))
      (message "Buffer is now parsable. Please save it.")))
  
--- 3745,3751 ----
            (bibtex-validate))
      (message "Starting to reformat entries...")
      (sit-for 2 nil t)
!     (bibtex-reformat read-options)
      (goto-char (point-max))
      (message "Buffer is now parsable. Please save it.")))
  
***************
*** 3890,3894 ****
  
  (provide 'bibtex)
  
! ;;; arch-tag: ee2be3af-caad-427f-b42a-d20fad630d04
  ;;; bibtex.el ends here
--- 3918,3922 ----
  
  (provide 'bibtex)
  
! ;; arch-tag: ee2be3af-caad-427f-b42a-d20fad630d04
  ;;; bibtex.el ends here




reply via email to

[Prev in Thread] Current Thread [Next in Thread]