Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id 393086DE1733 for ; Tue, 27 Oct 2015 02:05:37 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at cworth.org X-Spam-Flag: NO X-Spam-Score: -0.124 X-Spam-Level: X-Spam-Status: No, score=-0.124 tagged_above=-999 required=5 tests=[AWL=0.446, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_PASS=-0.001] autolearn=disabled Received: from arlo.cworth.org ([127.0.0.1]) by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 53f91SiiWBEI for ; Tue, 27 Oct 2015 02:05:35 -0700 (PDT) Received: from mail-wi0-f173.google.com (mail-wi0-f173.google.com [209.85.212.173]) by arlo.cworth.org (Postfix) with ESMTPS id E2FCA6DE13EF for ; Tue, 27 Oct 2015 02:05:34 -0700 (PDT) Received: by wicll6 with SMTP id ll6so149967543wic.1 for ; Tue, 27 Oct 2015 02:05:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=6YOP8beHAArwmZTj4i+0EcVohWzQRKcyC01X5S9uqI4=; b=W2disYO3WsNJZoB7UPcDZw6uGWbx26LJkky8OJco3Y7irMQJmrzGZhaf1a0+7x1DFI uQVRgkZcMCGngQoHJhUJhOIyzoVDL7p532uXeSY4hHVKp7GagPdOYtxoRhl+akB77IEH QUr+eaNEz5kbd/5Wgw6kmpE6kIGAgS/WqgvM3JX150c4veu3uDVbbvyMUJj88iSJZAF6 E0SjUtaNwVIxhfcxidzW50cldr7fTzDANieHvvd+LQfUcP9pOlc6w378KgqXJrozE6P+ Twl1Ua30QkDIB845BQRzxjKYUOnV0QdxeXU2urNiQXwen5TAoj9zb6Gw9bK0k2HER3wS SoDA== X-Received: by 10.194.59.137 with SMTP id z9mr25820928wjq.28.1445936731562; Tue, 27 Oct 2015 02:05:31 -0700 (PDT) Received: from localhost (5751dfa2.skybroadband.com. [87.81.223.162]) by smtp.gmail.com with ESMTPSA id q8sm16965563wiz.23.2015.10.27.02.05.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 27 Oct 2015 02:05:31 -0700 (PDT) From: Mark Walters To: notmuch@notmuchmail.org Subject: [PATCH (draft)] company model for external programs Date: Tue, 27 Oct 2015 09:05:28 +0000 Message-Id: <1445936728-30840-1-git-send-email-markwalters1009@gmail.com> X-Mailer: git-send-email 2.1.4 X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Oct 2015 09:05:37 -0000 --- This is an attempt to make company mode work for external address completion programs. We need to be able to run the address completion asynchronously. The changes are three fold: separate out the internal completion code into its own function, allow the external program to be called asynchronously, and copy the relevant code from the emacs function process-lines into our function as it doesn't appear to be available as a separate function. It seems to work in light testing but asynchronous emacs is always a little fragile/tricky. Best wishes Mark emacs/notmuch-address.el | 2 +- emacs/notmuch-company.el | 65 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/emacs/notmuch-address.el b/emacs/notmuch-address.el index 49e2402..65d04ce 100644 --- a/emacs/notmuch-address.el +++ b/emacs/notmuch-address.el @@ -81,7 +81,7 @@ (defcustom notmuch-address-use-company t (defun notmuch-address-setup () (let* ((use-company (and notmuch-address-use-company - (eq notmuch-address-command 'internal) + ;; (eq notmuch-address-command 'internal) (require 'company nil t))) (pair (cons notmuch-address-completion-headers-regexp (if use-company diff --git a/emacs/notmuch-company.el b/emacs/notmuch-company.el index add3161..dc3d018 100644 --- a/emacs/notmuch-company.el +++ b/emacs/notmuch-company.el @@ -42,6 +42,7 @@ (defvar company-backends) (declare-function notmuch-address-matching "notmuch-address") (defvar notmuch-address-full-harvest-finished) (defvar notmuch-address-completion-headers-regexp) +(defvar notmuch-address-command) ;;;###autoload (defun notmuch-company-setup () @@ -49,6 +50,54 @@ (defun notmuch-company-setup () (make-local-variable 'company-backends) (setq company-backends '(notmuch-company))) +(defun notmuch-company-address-internal (arg) + (cond + (notmuch-address-full-harvest-finished + ;; Update harvested addressed from time to time + (notmuch-address-harvest-trigger) + (notmuch-address-matching arg)) + (t + (cons :async + (lambda (callback) + ;; First run quick asynchronous harvest based on what the user entered so far + (notmuch-address-harvest + (format "to:%s*" arg) nil + (lambda (_proc _event) + (funcall callback (notmuch-address-matching arg)) + ;; Then start the (potentially long-running) full asynchronous harvest if necessary + (notmuch-address-harvest-trigger)))))))) + +(defun notmuch-company-external-sentinel (callback proc _event) + (let (lines) + (with-current-buffer (process-buffer proc) + ;; Copied verbatim from the process-lines function in subr.el in + ;; the standard emacs distribution. + (goto-char (point-min)) + (while (not (eobp)) + (setq lines (cons (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)) + lines)) + (forward-line 1)) + (message "lines %s" lines)) + (kill-buffer (process-buffer proc)) + (funcall callback (nreverse lines)))) + +(defun notmuch-company-address-external (arg) + (cons :async + (lambda (callback) + (let* ((buf (generate-new-buffer " *notmuch-external-address*")) + (proc (start-process "notmuch-external-address" buf + notmuch-address-command arg))) + (set-process-sentinel proc (apply-partially + 'notmuch-company-external-sentinel + callback)))))) + +(defun notmuch-company-address (arg) + (if (eq notmuch-address-command 'internal) + (notmuch-company-address-internal arg) + (notmuch-company-address-external arg))) + ;;;###autoload (defun notmuch-company (command &optional arg &rest _ignore) "`company-mode' completion back-end for `notmuch'." @@ -62,21 +111,7 @@ (defun notmuch-company (command &optional arg &rest _ignore) (looking-back (concat notmuch-address-completion-headers-regexp ".*") (line-beginning-position)) (setq notmuch-company-last-prefix (company-grab "[:,][ \t]*\\(.*\\)" 1 (point-at-bol))))) - (candidates (cond - (notmuch-address-full-harvest-finished - ;; Update harvested addressed from time to time - (notmuch-address-harvest-trigger) - (notmuch-address-matching arg)) - (t - (cons :async - (lambda (callback) - ;; First run quick asynchronous harvest based on what the user entered so far - (notmuch-address-harvest - (format "to:%s*" arg) nil - (lambda (_proc _event) - (funcall callback (notmuch-address-matching arg)) - ;; Then start the (potentially long-running) full asynchronous harvest if necessary - (notmuch-address-harvest-trigger)))))))) + (candidates (notmuch-company-address arg)) (match (if (string-match notmuch-company-last-prefix arg) (match-end 0) 0)) -- 2.1.4