From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Hongxu Chen Newsgroups: gmane.emacs.help Subject: Re: add-to-list with lexical variables Date: Sat, 08 Jun 2013 23:19:42 +0800 Message-ID: <874nd8hbox.fsf@gmail.com> References: <87txl8u68b.fsf@gmail.com> <87r4gcln2h.fsf@kuiper.lan.informatimago.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1370704811 19848 80.91.229.3 (8 Jun 2013 15:20:11 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 8 Jun 2013 15:20:11 +0000 (UTC) Cc: help-gnu-emacs@gnu.org To: "Pascal J. Bourguignon" Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Sat Jun 08 17:20:11 2013 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1UlKw6-0004C3-9W for geh-help-gnu-emacs@m.gmane.org; Sat, 08 Jun 2013 17:20:10 +0200 Original-Received: from localhost ([::1]:43406 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UlKw5-0004qf-Pl for geh-help-gnu-emacs@m.gmane.org; Sat, 08 Jun 2013 11:20:09 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:47066) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UlKvp-0004qY-3f for help-gnu-emacs@gnu.org; Sat, 08 Jun 2013 11:19:55 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UlKvm-0008Ac-6b for help-gnu-emacs@gnu.org; Sat, 08 Jun 2013 11:19:53 -0400 Original-Received: from mail-pa0-x22b.google.com ([2607:f8b0:400e:c03::22b]:36206) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UlKvl-0008AR-T2 for help-gnu-emacs@gnu.org; Sat, 08 Jun 2013 11:19:50 -0400 Original-Received: by mail-pa0-f43.google.com with SMTP id hz11so2441929pad.30 for ; Sat, 08 Jun 2013 08:19:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version:content-type; bh=GEP4oqQk1nBE9lP5h8jYCIhe1if/iUQ9YjTHeuM7ZJA=; b=VwONeAlSC+AuD4QTiAq2+IoQzMKXFJkPu3DoBattZMTiKNublG9SgXUbv1gEp+7H8F ZOGZYEFPGC9t6ylb7yUdMxO4gJKySWNNm3PBJWB1Gv/f9vZ6/NJImYZXVxvoZvDSvBst GgWvtIX6IFC2BFKUZt3uZd+UXoI0jTPxqsMMGuoO1WxJoj/rMhfkSXCuMucWTjHU36Jf j8aIswTJavw3RZPLUKWd30wuG98Dw7LhCWADaI22ApelzrtrXS3gidvLeKg4HJYhRTVm mGelm3fX3cwTsFnoP9B7+Gtm/QLR/Gz5ZxwdflRbKKadUCkDhI7fqNbqX3UJN/jqebtL 4zgQ== X-Received: by 10.66.122.8 with SMTP id lo8mr7094393pab.165.1370704788890; Sat, 08 Jun 2013 08:19:48 -0700 (PDT) Original-Received: from hongxuchen-VM.STAP ([167.220.224.198]) by mx.google.com with ESMTPSA id yj2sm3350874pbb.40.2013.06.08.08.19.46 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Sat, 08 Jun 2013 08:19:48 -0700 (PDT) In-Reply-To: <87r4gcln2h.fsf@kuiper.lan.informatimago.com> (Pascal J. Bourguignon's message of "Sat, 08 Jun 2013 16:00:22 +0200") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400e:c03::22b X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:91396 Archived-At: "Pascal J. Bourguignon" writes: > Hongxu Chen writes: > >> Hi list, >> >> I am writing a snippet to add element into environment variables, and >> it is written as below: >> >> #+BEGIN_SRC elisp >> (defun no-dup-add-env-ele (env env-ele-string) >> (let* ((env-separator (if (string-equal system-type "windows-nt") ";" ":")) >> (env-list (split-string (getenv env) env-separator))) >> (if (string-match-p env-separator env-ele-string) >> (dolist (env-ele (split-string env-ele-string env-separator)) >> (add-to-list 'env-list env-ele)) >> (add-to-list 'env-list env-ele-string)) >> (setenv env (mapconcat 'identity env-list ":")))) >> #+END_SRC >> >> 1. when I set `lexical-binding' to t and byte-compile the file, it >> would report this error: >> >> add-to-list cannot use lexical var `env-list' >> >> 2. And when I using `lexical-let*' instead, there would be an warning: >> >> Warning: assignment to free variable `env-list' >> >> 3. However after resetting `lexical-binding' to nil, byte-compiles well. >> >> So what are the differences? > > The difference is not. > > (not t) --> nil > (not nil) --> t > > or: > > not lexical binding is dynamic binding. > not dynamic binding is lexical binding. > > > Now, to add new elements to a list bound to some place, there's the > pushnew cl operator (a macro). push can be used to push > unconditionnaly, and pop to remove the first element from a list bound > to a place. That's how things have to be done with lexical binding. > > > (require 'cl) > > (defun* pushnew/envvar (env-ele-string env &key (test (function equal))) > (let* ((env-separator (if (member system-type '(windows-nt ms-dos)) ";" ":")) > (env-list (split-string (or (getenv env) "") env-separator t))) > (dolist (env-ele (split-string env-ele-string env-separator)) > (pushnew env-ele env-list :test test)) > (setenv env (mapconcat 'identity env-list env-separator)))) > > (defun test/pushnew/envvar () > (setenv "TEST" nil) > (assert (equal (pushnew/envvar "A:B:C" "TEST") > "C:B:A")) > (assert (equal (getenv "TEST") > "C:B:A")) > (assert (equal (pushnew/envvar "D:E:F" "TEST") > "F:E:D:C:B:A")) > (assert (equal (getenv "TEST") > "F:E:D:C:B:A")) > (assert (equal (pushnew/envvar "G" "TEST") > "G:F:E:D:C:B:A")) > (assert (equal (getenv "TEST") > "G:F:E:D:C:B:A")) > (assert (equal (pushnew/envvar "G:F:E:D:C:B:A" "TEST") > "G:F:E:D:C:B:A")) > (assert (equal (pushnew/envvar "X:F:Y:D:Z:B" "TEST") > "Z:Y:X:G:F:E:D:C:B:A")) > (assert (equal (pushnew/envvar "a:b:c:d" "TEST") > "d:c:b:a:Z:Y:X:G:F:E:D:C:B:A")) > (assert (equal (pushnew/envvar "x:y:z" "TEST" :test (function equalp)) > "d:c:b:a:Z:Y:X:G:F:E:D:C:B:A")) > :success) > > (test/pushnew/envvar) > --> :success > > > You have to add a test argument, since for some environment variables, > and for some values, you may want to do case insensitive, or more > complex comparison. > > For example, if you mount a MS-DOS file system on a case sensitive unix file > system, itself mounted a HFS+ case insensitive file system, you will > have to compare parts of the path case sensitively, and parts case > insensitively: > > > mount /dev/disk1s1 /Volumes/case-sensitive > mount /dev/disk2s1 /Volumes/case-sensitive/mnt/ms-dos > > Now, /VOLUMES/case-sensitive/mnt/ms-dos/DESCENT > is the same path as: > /Volumes/case-sensitive/mnt/ms-dos/Descent > but not the same as: > /Volumes/case-sensitive/MNT/ms-dos/descent > Perhaps there are both > /Volumes/case-sensitive/MNT > and: > /Volumes/case-sensitive/mnt > on the case sensitive file system! > > so you will have to write: > > (pushnew/envvar "/Volumes/case-sensitive/mnt/ms-dos/Descent" > "PATH" > :test (function file-system-sensitive-path-equal-p)) > > with: > > (defun file-system-sensitive-path-equal-p (a b) > (labels ((compare-path (curdir ac bc) > (cond > ((null ac) (null bc)) > ((null bc) nil) > (t > (and (funcall (if (case-sensitive-file-system-at-path-p curdir) > (function equal) > (function equalp)) > (car ac) (car ab)) > (compare-path (path-append curdir (car ac)) > (cdr ac) (cdr bc))))))) > (compare-path "/" > (split-path (expand-file-name a)) > (split-path (expand-file-name b))))) > > > So that if there's already > > /Volumes/case-sensitive/mnt/ms-dos/DESCENT > > on PATH, > > (pushnew/envvar "/VOLUMES/case-sensitive/mnt/ms-dos/Descent" > "PATH" > :test (function file-system-sensitive-path-equal-p)) > > won't add it, but: > > (pushnew/envvar "/Volumes/case-sensitive/mnt/MS-DOS/DESCENT" > "PATH" > :test (function file-system-sensitive-path-equal-p)) > > will. Thanks so much for your instruction. I now feel that there are really so many flaws in my snippet. However I still don't know the difference `lexical-binding' and `lexical-let' brings. Are there some authoritative introductions/tutorials? Regards, Hongxu Chen