+;;;; Completion.
+
+(defun python-symbol-completions (symbol)
+ "Return a list of completions of the string SYMBOL from Python process.
+The list is sorted."
+ (when symbol
+ (let ((completions
+ (condition-case ()
+ (car (read-from-string (python-send-receive
+ (format "emacs.complete(%S)" symbol))))
+ (error nil))))
+ (sort
+ ;; We can get duplicates from the above -- don't know why.
+ (delete-dups completions)
+ #'string<))))
+
+(defun python-partial-symbol ()
+ "Return the partial symbol before point (for completion)."
+ (let ((end (point))
+ (start (save-excursion
+ (and (re-search-backward
+ (rx (and (or buffer-start (regexp "[^[:alnum:]._]"))
+ (group (1+ (regexp "[[:alnum:]._]")))
+ point))
+ nil t)
+ (match-beginning 1)))))
+ (if start (buffer-substring-no-properties start end))))
+
+;; Fixme: We should have an abstraction of this sort of thing in the
+;; core.
+(defun python-complete-symbol ()
+ "Perform completion on the Python symbol preceding point.
+Repeating the command scrolls the completion window."
+ (interactive)
+ (let ((window (get-buffer-window "*Completions*")))
+ (if (and (eq last-command this-command)
+ window (window-live-p window) (window-buffer window)
+ (buffer-name (window-buffer window)))
+ (with-current-buffer (window-buffer window)
+ (if (pos-visible-in-window-p (point-max) window)
+ (set-window-start window (point-min))
+ (save-selected-window
+ (select-window window)
+ (scroll-up))))
+ ;; Do completion.
+ (let* ((end (point))
+ (symbol (python-partial-symbol))
+ (completions (python-symbol-completions symbol))
+ (completion (if completions
+ (try-completion symbol completions))))
+ (when symbol
+ (cond ((eq completion t))
+ ((null completion)
+ (message "Can't find completion for \"%s\"" symbol)
+ (ding))
+ ((not (string= symbol completion))
+ (delete-region (- end (length symbol)) end)
+ (insert completion))
+ (t
+ (message "Making completion list...")
+ (with-output-to-temp-buffer "*Completions*"
+ (display-completion-list completions))
+ (message "Making completion list...%s" "done"))))))))
+
+(eval-when-compile (require 'hippie-exp))
+
+(defun python-try-complete (old)
+ "Completion function for Python for use with `hippie-expand'."
+ (when (eq major-mode 'python-mode) ; though we only add it locally
+ (unless old
+ (let ((symbol (python-partial-symbol)))
+ (he-init-string (- (point) (length symbol)) (point))
+ (if (not (he-string-member he-search-string he-tried-table))
+ (push he-search-string he-tried-table))
+ (setq he-expand-list
+ (and symbol (python-symbol-completions symbol)))))
+ (while (and he-expand-list
+ (he-string-member (car he-expand-list) he-tried-table))
+ (pop he-expand-list))
+ (if he-expand-list
+ (progn
+ (he-substitute-string (pop he-expand-list))
+ t)
+ (if old (he-reset-string))
+ nil)))
+\f