aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStefan Monnier2008-05-13 05:16:43 +0000
committerStefan Monnier2008-05-13 05:16:43 +0000
commit3271a8f56cca6dc132ee3af157e87ab8faf42ab8 (patch)
tree7273e7da207cfa9816c7aa38a3b81edcf44fd4a9 /src
parentf836b98e3139ff39834ceb2dcc4852c1c3e068c9 (diff)
downloademacs-3271a8f56cca6dc132ee3af157e87ab8faf42ab8.tar.gz
emacs-3271a8f56cca6dc132ee3af157e87ab8faf42ab8.zip
(file_name_completion): Tweak the code so as to always do it
in a single pass. Tighten the scope of some variables.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog3
-rw-r--r--src/dired.c315
2 files changed, 164 insertions, 154 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 86bc2e171ae..31bf04624b0 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,8 @@
12008-05-13 Stefan Monnier <monnier@iro.umontreal.ca> 12008-05-13 Stefan Monnier <monnier@iro.umontreal.ca>
2 2
3 * dired.c (file_name_completion): Tweak the code so as to always do it
4 in a single pass. Tighten the scope of some variables.
5
3 * dired.c (Qdefault_directory): New var. 6 * dired.c (Qdefault_directory): New var.
4 (file_name_completion): Use it instead of Fexpand_file_name. 7 (file_name_completion): Use it instead of Fexpand_file_name.
5 (syms_of_dired): Initialize it. 8 (syms_of_dired): Initialize it.
diff --git a/src/dired.c b/src/dired.c
index f25f24e8e47..12e7d54ebd4 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -466,8 +466,7 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
466 Lisp_Object predicate; 466 Lisp_Object predicate;
467{ 467{
468 DIR *d; 468 DIR *d;
469 int bestmatchsize = 0, skip; 469 int bestmatchsize = 0;
470 register int compare, matchsize;
471 int matchcount = 0; 470 int matchcount = 0;
472 /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded. 471 /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded.
473 If ALL_FLAG is 0, BESTMATCH is either nil 472 If ALL_FLAG is 0, BESTMATCH is either nil
@@ -477,7 +476,10 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
477 Lisp_Object encoded_dir; 476 Lisp_Object encoded_dir;
478 struct stat st; 477 struct stat st;
479 int directoryp; 478 int directoryp;
480 int passcount; 479 /* If includeall is zero, exclude files in completion-ignored-extensions as
480 well as "." and "..". Until shown otherwise, assume we can't exclude
481 anything. */
482 int includeall = 1;
481 int count = SPECPDL_INDEX (); 483 int count = SPECPDL_INDEX ();
482 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; 484 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
483 485
@@ -518,76 +520,71 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
518 520
519 encoded_dir = ENCODE_FILE (dirname); 521 encoded_dir = ENCODE_FILE (dirname);
520 522
521 /* With passcount = 0, ignore files that end in an ignored extension. 523 BLOCK_INPUT;
522 If nothing found then try again with passcount = 1, don't ignore them. 524 d = opendir (SDATA (Fdirectory_file_name (encoded_dir)));
523 If looking for all completions, start with passcount = 1, 525 UNBLOCK_INPUT;
524 so always take even the ignored ones. 526 if (!d)
527 report_file_error ("Opening directory", Fcons (dirname, Qnil));
525 528
526 ** It would not actually be helpful to the user to ignore any possible 529 record_unwind_protect (directory_files_internal_unwind,
527 completions when making a list of them.** */ 530 make_save_value (d, 0));
528 531
529 for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++) 532 /* Loop reading blocks */
533 /* (att3b compiler bug requires do a null comparison this way) */
534 while (1)
530 { 535 {
531 int inner_count = SPECPDL_INDEX (); 536 DIRENTRY *dp;
532 537 int len;
533 BLOCK_INPUT; 538 int canexclude = 0;
534 d = opendir (SDATA (Fdirectory_file_name (encoded_dir)));
535 UNBLOCK_INPUT;
536 if (!d)
537 report_file_error ("Opening directory", Fcons (dirname, Qnil));
538
539 record_unwind_protect (directory_files_internal_unwind,
540 make_save_value (d, 0));
541
542 /* Loop reading blocks */
543 /* (att3b compiler bug requires do a null comparison this way) */
544 while (1)
545 {
546 DIRENTRY *dp;
547 int len;
548 539
549#ifdef VMS 540#ifdef VMS
550 dp = (*readfunc) (d); 541 dp = (*readfunc) (d);
551#else 542#else
552 errno = 0; 543 errno = 0;
553 dp = readdir (d); 544 dp = readdir (d);
554 if (dp == NULL && (0 545 if (dp == NULL && (0
555# ifdef EAGAIN 546# ifdef EAGAIN
556 || errno == EAGAIN 547 || errno == EAGAIN
557# endif 548# endif
558# ifdef EINTR 549# ifdef EINTR
559 || errno == EINTR 550 || errno == EINTR
560# endif 551# endif
561 )) 552 ))
562 { QUIT; continue; } 553 { QUIT; continue; }
563#endif 554#endif
564 555
565 if (!dp) break; 556 if (!dp) break;
566 557
567 len = NAMLEN (dp); 558 len = NAMLEN (dp);
568 559
569 QUIT; 560 QUIT;
570 if (! DIRENTRY_NONEMPTY (dp) 561 if (! DIRENTRY_NONEMPTY (dp)
571 || len < SCHARS (encoded_file) 562 || len < SCHARS (encoded_file)
572 || 0 <= scmp (dp->d_name, SDATA (encoded_file), 563 || 0 <= scmp (dp->d_name, SDATA (encoded_file),
573 SCHARS (encoded_file))) 564 SCHARS (encoded_file)))
574 continue; 565 continue;
575 566
576 if (file_name_completion_stat (encoded_dir, dp, &st) < 0) 567 if (file_name_completion_stat (encoded_dir, dp, &st) < 0)
577 continue; 568 continue;
578 569
579 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR); 570 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
580 tem = Qnil; 571 tem = Qnil;
581 if (directoryp) 572 /* If all_flag is set, always include all.
573 It would not actually be helpful to the user to ignore any possible
574 completions when making a list of them. */
575 if (!all_flag)
576 {
577 int skip;
578 if (directoryp)
582 { 579 {
583#ifndef TRIVIAL_DIRECTORY_ENTRY 580#ifndef TRIVIAL_DIRECTORY_ENTRY
584#define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, "..")) 581#define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
585#endif 582#endif
586 /* "." and ".." are never interesting as completions, and are 583 /* "." and ".." are never interesting as completions, and are
587 actually in the way in a directory with only one file. */ 584 actually in the way in a directory with only one file. */
588 if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name)) 585 if (TRIVIAL_DIRECTORY_ENTRY (dp->d_name))
589 continue; 586 canexclude = 1;
590 if (!passcount && len > SCHARS (encoded_file)) 587 else if (len > SCHARS (encoded_file))
591 /* Ignore directories if they match an element of 588 /* Ignore directories if they match an element of
592 completion-ignored-extensions which ends in a slash. */ 589 completion-ignored-extensions which ends in a slash. */
593 for (tem = Vcompletion_ignored_extensions; 590 for (tem = Vcompletion_ignored_extensions;
@@ -618,10 +615,10 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
618 } 615 }
619 } 616 }
620 else 617 else
621 { 618 {
622 /* Compare extensions-to-be-ignored against end of this file name */ 619 /* Compare extensions-to-be-ignored against end of this file name */
623 /* if name is not an exact match against specified string */ 620 /* if name is not an exact match against specified string */
624 if (!passcount && len > SCHARS (encoded_file)) 621 if (len > SCHARS (encoded_file))
625 /* and exit this for loop if a match is found */ 622 /* and exit this for loop if a match is found */
626 for (tem = Vcompletion_ignored_extensions; 623 for (tem = Vcompletion_ignored_extensions;
627 CONSP (tem); tem = XCDR (tem)) 624 CONSP (tem); tem = XCDR (tem))
@@ -644,121 +641,131 @@ file_name_completion (file, dirname, all_flag, ver_flag, predicate)
644 641
645 /* If an ignored-extensions match was found, 642 /* If an ignored-extensions match was found,
646 don't process this name as a completion. */ 643 don't process this name as a completion. */
647 if (!passcount && CONSP (tem)) 644 if (CONSP (tem))
648 continue; 645 canexclude = 1;
649 646
650 /* FIXME: If we move this `decode' earlier we can eliminate 647 if (!includeall && canexclude)
651 the repeated ENCODE_FILE on Vcompletion_ignored_extensions. */ 648 /* We're not including all files and this file can be excluded. */
652 name = make_unibyte_string (dp->d_name, len); 649 continue;
653 name = DECODE_FILE (name);
654 650
655 if (!passcount) 651 if (includeall && !canexclude)
656 { 652 { /* If we have one non-excludable file, we want to exclude the
657 Lisp_Object regexps; 653 excudable files. */
658 Lisp_Object zero; 654 includeall = 0;
659 XSETFASTINT (zero, 0); 655 /* Throw away any previous excludable match found. */
660 656 bestmatch = Qnil;
661 /* Ignore this element if it fails to match all the regexps. */ 657 bestmatchsize = 0;
662 for (regexps = Vcompletion_regexp_list; CONSP (regexps); 658 matchcount = 0;
663 regexps = XCDR (regexps))
664 if (fast_string_match (XCAR (regexps), name) < 0)
665 break;
666 if (CONSP (regexps))
667 continue;
668 } 659 }
660 }
661 /* FIXME: If we move this `decode' earlier we can eliminate
662 the repeated ENCODE_FILE on Vcompletion_ignored_extensions. */
663 name = make_unibyte_string (dp->d_name, len);
664 name = DECODE_FILE (name);
665
666 {
667 Lisp_Object regexps;
668 Lisp_Object zero;
669 XSETFASTINT (zero, 0);
670
671 /* Ignore this element if it fails to match all the regexps. */
672 for (regexps = Vcompletion_regexp_list; CONSP (regexps);
673 regexps = XCDR (regexps))
674 if (fast_string_match (XCAR (regexps), name) < 0)
675 break;
676 if (CONSP (regexps))
677 continue;
678 }
679
680 /* This is a possible completion */
681 if (directoryp)
682 /* This completion is a directory; make it end with '/'. */
683 name = Ffile_name_as_directory (name);
684
685 /* Test the predicate, if any. */
686 if (!NILP (predicate))
687 {
688 Lisp_Object val;
689 struct gcpro gcpro1;
669 690
670 /* This is a possible completion */ 691 GCPRO1 (name);
671 if (directoryp) 692 val = call1 (predicate, name);
672 /* This completion is a directory; make it end with '/'. */ 693 UNGCPRO;
673 name = Ffile_name_as_directory (name);
674
675 /* Test the predicate, if any. */
676 if (!NILP (predicate))
677 {
678 Lisp_Object val;
679 struct gcpro gcpro1;
680
681 GCPRO1 (name);
682 val = call1 (predicate, name);
683 UNGCPRO;
684 694
685 if (NILP (val)) 695 if (NILP (val))
686 continue; 696 continue;
687 } 697 }
688 698
689 /* Suitably record this match. */ 699 /* Suitably record this match. */
690 700
691 matchcount++; 701 matchcount++;
692 702
693 if (all_flag) 703 if (all_flag)
694 bestmatch = Fcons (name, bestmatch); 704 bestmatch = Fcons (name, bestmatch);
695 else if (NILP (bestmatch)) 705 else if (NILP (bestmatch))
696 { 706 {
697 bestmatch = name; 707 bestmatch = name;
698 bestmatchsize = SCHARS (name); 708 bestmatchsize = SCHARS (name);
699 } 709 }
700 else 710 else
711 {
712 Lisp_Object zero = make_number (0);
713 /* FIXME: This is a copy of the code in Ftry_completion. */
714 int compare = min (bestmatchsize, SCHARS (name));
715 Lisp_Object tem
716 = Fcompare_strings (bestmatch, zero,
717 make_number (compare),
718 name, zero,
719 make_number (compare),
720 completion_ignore_case ? Qt : Qnil);
721 int matchsize
722 = (EQ (tem, Qt) ? compare
723 : XINT (tem) < 0 ? - XINT (tem) - 1
724 : XINT (tem) - 1);
725
726 if (completion_ignore_case)
701 { 727 {
702 Lisp_Object zero = make_number (0); 728 /* If this is an exact match except for case,
703 /* FIXME: This is a copy of the code in Ftry_completion. */ 729 use it as the best match rather than one that is not
704 compare = min (bestmatchsize, SCHARS (name)); 730 an exact match. This way, we get the case pattern
705 tem = Fcompare_strings (bestmatch, zero, 731 of the actual match. */
706 make_number (compare), 732 /* This tests that the current file is an exact match
707 name, zero, 733 but BESTMATCH is not (it is too long). */
708 make_number (compare), 734 if ((matchsize == SCHARS (name)
709 completion_ignore_case ? Qt : Qnil); 735 && matchsize + !!directoryp
710 if (EQ (tem, Qt)) 736 < SCHARS (bestmatch))
711 matchsize = compare; 737 ||
712 else if (XINT (tem) < 0) 738 /* If there is no exact match ignoring case,
713 matchsize = - XINT (tem) - 1; 739 prefer a match that does not change the case
714 else 740 of the input. */
715 matchsize = XINT (tem) - 1; 741 /* If there is more than one exact match aside from
716 742 case, and one of them is exact including case,
717 if (completion_ignore_case) 743 prefer that one. */
718 { 744 /* This == checks that, of current file and BESTMATCH,
719 /* If this is an exact match except for case, 745 either both or neither are exact. */
720 use it as the best match rather than one that is not 746 (((matchsize == SCHARS (name))
721 an exact match. This way, we get the case pattern 747 ==
722 of the actual match. */ 748 (matchsize + !!directoryp == SCHARS (bestmatch)))
723 /* This tests that the current file is an exact match 749 && (tem = Fcompare_strings (name, zero,
724 but BESTMATCH is not (it is too long). */ 750 make_number (SCHARS (file)),
725 if ((matchsize == SCHARS (name) 751 file, zero,
726 && matchsize + !!directoryp 752 Qnil,
727 < SCHARS (bestmatch)) 753 Qnil),
728 || 754 EQ (Qt, tem))
729 /* If there is no exact match ignoring case, 755 && (tem = Fcompare_strings (bestmatch, zero,
730 prefer a match that does not change the case 756 make_number (SCHARS (file)),
731 of the input. */ 757 file, zero,
732 /* If there is more than one exact match aside from 758 Qnil,
733 case, and one of them is exact including case, 759 Qnil),
734 prefer that one. */ 760 ! EQ (Qt, tem))))
735 /* This == checks that, of current file and BESTMATCH, 761 bestmatch = name;
736 either both or neither are exact. */
737 (((matchsize == SCHARS (name))
738 ==
739 (matchsize + !!directoryp == SCHARS (bestmatch)))
740 && (tem = Fcompare_strings (name, zero,
741 make_number (SCHARS (file)),
742 file, zero,
743 Qnil,
744 Qnil),
745 EQ (Qt, tem))
746 && (tem = Fcompare_strings (bestmatch, zero,
747 make_number (SCHARS (file)),
748 file, zero,
749 Qnil,
750 Qnil),
751 ! EQ (Qt, tem))))
752 bestmatch = name;
753 }
754 bestmatchsize = matchsize;
755 } 762 }
763 bestmatchsize = matchsize;
756 } 764 }
757 /* This closes the directory. */
758 bestmatch = unbind_to (inner_count, bestmatch);
759 } 765 }
760 766
761 UNGCPRO; 767 UNGCPRO;
768 /* This closes the directory. */
762 bestmatch = unbind_to (count, bestmatch); 769 bestmatch = unbind_to (count, bestmatch);
763 770
764 if (all_flag || NILP (bestmatch)) 771 if (all_flag || NILP (bestmatch))