+(defun company--fetch-candidates (prefix)
+ (let ((c (if company--manual-action
+ (company-call-backend 'candidates prefix)
+ (company-call-backend-raw 'candidates prefix)))
+ res)
+ (if (not (eq (car c) :async))
+ c
+ (let ((buf (current-buffer))
+ (win (selected-window))
+ (tick (buffer-chars-modified-tick))
+ (pt (point))
+ (backend company-backend))
+ (funcall
+ (cdr c)
+ (lambda (candidates)
+ (if (not (and candidates (eq res 'done)))
+ ;; There's no completions to display,
+ ;; or the fetcher called us back right away.
+ (setq res candidates)
+ (setq company-backend backend
+ company-candidates-cache
+ (list (cons prefix
+ (company--preprocess-candidates candidates))))
+ (company-idle-begin buf win tick pt)))))
+ ;; FIXME: Relying on the fact that the callers
+ ;; will interpret nil as "do nothing" is shaky.
+ ;; A throw-catch would be one possible improvement.
+ (or res
+ (progn (setq res 'done) nil)))))
+
+(defun company--preprocess-candidates (candidates)
+ (unless (company-call-backend 'sorted)
+ (setq candidates (sort candidates 'string<)))
+ (when (company-call-backend 'duplicates)
+ (company--strip-duplicates candidates))
+ candidates)
+
+(defun company--postprocess-candidates (candidates)
+ (when (or company-candidates-predicate company-transformers)
+ (setq candidates (copy-sequence candidates)))
+ (when company-candidates-predicate
+ (setq candidates (cl-delete-if-not company-candidates-predicate candidates)))
+ (company--transform-candidates candidates))
+
+(defun company--strip-duplicates (candidates)
+ (let ((c2 candidates)
+ (annos 'unk))
+ (while c2
+ (setcdr c2
+ (let ((str (pop c2)))
+ (while (let ((str2 (car c2)))
+ (if (not (equal str str2))
+ (progn
+ (setq annos 'unk)
+ nil)
+ (when (eq annos 'unk)
+ (setq annos (list (company-call-backend
+ 'annotation str))))
+ (let ((anno2 (company-call-backend
+ 'annotation str2)))
+ (if (member anno2 annos)
+ t
+ (push anno2 annos)
+ nil))))
+ (pop c2))
+ c2)))))
+
+(defun company--transform-candidates (candidates)
+ (let ((c candidates))
+ (dolist (tr company-transformers)
+ (setq c (funcall tr c)))
+ c))
+
+(defcustom company-occurrence-weight-function
+ #'company-occurrence-prefer-closest-above
+ "Function to weigh matches in `company-sort-by-occurrence'.
+It's called with three arguments: cursor position, the beginning and the
+end of the match."
+ :type '(choice
+ (const :tag "First above point, then below point"
+ company-occurrence-prefer-closest-above)
+ (const :tag "Prefer closest in any direction"
+ company-occurrence-prefer-any-closest)))
+
+(defun company-occurrence-prefer-closest-above (pos match-beg match-end)
+ "Give priority to the matches above point, then those below point."
+ (if (< match-beg pos)
+ (- pos match-end)
+ (- match-beg (window-start))))
+
+(defun company-occurrence-prefer-any-closest (pos _match-beg match-end)
+ "Give priority to the matches closest to the point."
+ (abs (- pos match-end)))
+
+(defun company-sort-by-occurrence (candidates)
+ "Sort CANDIDATES according to their occurrences.
+Searches for each in the currently visible part of the current buffer and
+prioritizes the matches according to `company-occurrence-weight-function'.
+The rest of the list is appended unchanged.
+Keywords and function definition names are ignored."
+ (let* ((w-start (window-start))
+ (w-end (window-end))
+ (start-point (point))
+ occurs
+ (noccurs
+ (save-excursion
+ (cl-delete-if
+ (lambda (candidate)
+ (when (catch 'done
+ (goto-char w-start)
+ (while (search-forward candidate w-end t)
+ (when (and (not (eq (point) start-point))
+ (save-match-data
+ (company--occurrence-predicate)))
+ (throw 'done t))))
+ (push
+ (cons candidate
+ (funcall company-occurrence-weight-function
+ start-point
+ (match-beginning 0)
+ (match-end 0)))
+ occurs)
+ t))
+ candidates))))
+ (nconc
+ (mapcar #'car (sort occurs (lambda (e1 e2) (<= (cdr e1) (cdr e2)))))
+ noccurs)))
+
+(defun company--occurrence-predicate ()
+ (let ((beg (match-beginning 0))
+ (end (match-end 0)))
+ (save-excursion
+ (goto-char end)
+ (and (not (memq (get-text-property (1- (point)) 'face)
+ '(font-lock-function-name-face
+ font-lock-keyword-face)))
+ (let ((prefix (company--prefix-str
+ (company-call-backend 'prefix))))
+ (and (stringp prefix)
+ (= (length prefix) (- end beg))))))))
+
+(defun company-sort-by-backend-importance (candidates)
+ "Sort CANDIDATES as two priority groups.
+If `company-backend' is a function, do nothing. If it's a list, move
+candidates from back-ends before keyword `:with' to the front. Candidates
+from the rest of the back-ends in the group, if any, will be left at the end."
+ (if (functionp company-backend)
+ candidates
+ (let ((low-priority (cdr (memq :with company-backend))))
+ (if (null low-priority)
+ candidates
+ (sort candidates
+ (lambda (c1 c2)
+ (and
+ (let ((b2 (get-text-property 0 'company-backend c2)))
+ (and b2 (memq b2 low-priority)))
+ (let ((b1 (get-text-property 0 'company-backend c1)))
+ (or (not b1) (not (memq b1 low-priority)))))))))))
+