Mercurial > vim
comparison src/search.c @ 18426:3b80bdbdc832 v8.1.2207
patch 8.1.2207: "gn" doesn't work quite right
Commit: https://github.com/vim/vim/commit/edaad6e0a0e3c1fcb6a5c2771e647c52475bb19c
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Oct 24 15:23:37 2019 +0200
patch 8.1.2207: "gn" doesn't work quite right
Problem: "gn" doesn't work quite right. (Jaehwang Jerry Jung)
Solution: Improve and simplify the search logic. (Christian Brabandt,
closes #5103, closes #5075)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 24 Oct 2019 15:30:03 +0200 |
parents | 7b4d9e1377ee |
children | 35e0ab1f2975 |
comparison
equal
deleted
inserted
replaced
18425:d58c4ff92b3f | 18426:3b80bdbdc832 |
---|---|
4674 return FALSE; | 4674 return FALSE; |
4675 } | 4675 } |
4676 | 4676 |
4677 #endif /* FEAT_TEXTOBJ */ | 4677 #endif /* FEAT_TEXTOBJ */ |
4678 | 4678 |
4679 static int is_one_char(char_u *pattern, int move, pos_T *cur, int direction); | 4679 /* |
4680 * Check if the pattern is one character long or zero-width. | |
4681 * If move is TRUE, check from the beginning of the buffer, else from position | |
4682 * "cur". | |
4683 * "direction" is FORWARD or BACKWARD. | |
4684 * Returns TRUE, FALSE or -1 for failure. | |
4685 */ | |
4686 static int | |
4687 is_zero_width(char_u *pattern, int move, pos_T *cur, int direction) | |
4688 { | |
4689 regmmatch_T regmatch; | |
4690 int nmatched = 0; | |
4691 int result = -1; | |
4692 pos_T pos; | |
4693 int save_called_emsg = called_emsg; | |
4694 int flag = 0; | |
4695 | |
4696 if (pattern == NULL) | |
4697 pattern = spats[last_idx].pat; | |
4698 | |
4699 if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH, | |
4700 SEARCH_KEEP, ®match) == FAIL) | |
4701 return -1; | |
4702 | |
4703 // init startcol correctly | |
4704 regmatch.startpos[0].col = -1; | |
4705 // move to match | |
4706 if (move) | |
4707 { | |
4708 CLEAR_POS(&pos); | |
4709 } | |
4710 else | |
4711 { | |
4712 pos = *cur; | |
4713 // accept a match at the cursor position | |
4714 flag = SEARCH_START; | |
4715 } | |
4716 | |
4717 if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1, | |
4718 SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) | |
4719 { | |
4720 // Zero-width pattern should match somewhere, then we can check if | |
4721 // start and end are in the same position. | |
4722 called_emsg = FALSE; | |
4723 do | |
4724 { | |
4725 regmatch.startpos[0].col++; | |
4726 nmatched = vim_regexec_multi(®match, curwin, curbuf, | |
4727 pos.lnum, regmatch.startpos[0].col, NULL, NULL); | |
4728 if (nmatched != 0) | |
4729 break; | |
4730 } while (direction == FORWARD ? regmatch.startpos[0].col < pos.col | |
4731 : regmatch.startpos[0].col > pos.col); | |
4732 | |
4733 if (!called_emsg) | |
4734 { | |
4735 result = (nmatched != 0 | |
4736 && regmatch.startpos[0].lnum == regmatch.endpos[0].lnum | |
4737 && regmatch.startpos[0].col == regmatch.endpos[0].col); | |
4738 } | |
4739 } | |
4740 | |
4741 called_emsg |= save_called_emsg; | |
4742 vim_regfree(regmatch.regprog); | |
4743 return result; | |
4744 } | |
4745 | |
4680 | 4746 |
4681 /* | 4747 /* |
4682 * Find next search match under cursor, cursor at end. | 4748 * Find next search match under cursor, cursor at end. |
4683 * Used while an operator is pending, and in Visual mode. | 4749 * Used while an operator is pending, and in Visual mode. |
4684 */ | 4750 */ |
4695 int dir; | 4761 int dir; |
4696 int result; // result of various function calls | 4762 int result; // result of various function calls |
4697 char_u old_p_ws = p_ws; | 4763 char_u old_p_ws = p_ws; |
4698 int flags = 0; | 4764 int flags = 0; |
4699 pos_T save_VIsual = VIsual; | 4765 pos_T save_VIsual = VIsual; |
4700 int one_char; | 4766 int zero_width; |
4701 | 4767 |
4702 /* wrapping should not occur */ | 4768 /* wrapping should not occur */ |
4703 p_ws = FALSE; | 4769 p_ws = FALSE; |
4704 | 4770 |
4705 /* Correct cursor when 'selection' is exclusive */ | 4771 /* Correct cursor when 'selection' is exclusive */ |
4706 if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor)) | 4772 if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor)) |
4707 dec_cursor(); | 4773 dec_cursor(); |
4708 | 4774 |
4775 orig_pos = pos = curwin->w_cursor; | |
4709 if (VIsual_active) | 4776 if (VIsual_active) |
4710 { | 4777 { |
4711 orig_pos = curwin->w_cursor; | 4778 if (forward) |
4712 | 4779 incl(&pos); |
4713 pos = curwin->w_cursor; | 4780 else |
4714 | 4781 decl(&pos); |
4715 /* make sure, searching further will extend the match */ | 4782 } |
4716 if (VIsual_active) | |
4717 { | |
4718 if (forward) | |
4719 incl(&pos); | |
4720 else | |
4721 decl(&pos); | |
4722 } | |
4723 } | |
4724 else | |
4725 orig_pos = pos = curwin->w_cursor; | |
4726 | 4783 |
4727 /* Is the pattern is zero-width?, this time, don't care about the direction | 4784 /* Is the pattern is zero-width?, this time, don't care about the direction |
4728 */ | 4785 */ |
4729 one_char = is_one_char(spats[last_idx].pat, TRUE, &curwin->w_cursor, | 4786 zero_width = is_zero_width(spats[last_idx].pat, TRUE, &curwin->w_cursor, |
4730 FORWARD); | 4787 FORWARD); |
4731 if (one_char == -1) | 4788 if (zero_width == -1) |
4732 { | 4789 { |
4733 p_ws = old_p_ws; | 4790 p_ws = old_p_ws; |
4734 return FAIL; /* pattern not found */ | 4791 return FAIL; /* pattern not found */ |
4735 } | 4792 } |
4736 | 4793 |
4745 dir = i; | 4802 dir = i; |
4746 else | 4803 else |
4747 dir = !i; | 4804 dir = !i; |
4748 | 4805 |
4749 flags = 0; | 4806 flags = 0; |
4750 if (!dir && !one_char) | 4807 if (!dir && !zero_width) |
4751 flags = SEARCH_END; | 4808 flags = SEARCH_END; |
4752 end_pos = pos; | 4809 end_pos = pos; |
4753 | 4810 |
4754 result = searchit(curwin, curbuf, &pos, &end_pos, | 4811 result = searchit(curwin, curbuf, &pos, &end_pos, |
4755 (dir ? FORWARD : BACKWARD), | 4812 (dir ? FORWARD : BACKWARD), |
4782 pos.lnum = curwin->w_buffer->b_ml.ml_line_count; | 4839 pos.lnum = curwin->w_buffer->b_ml.ml_line_count; |
4783 pos.col = (colnr_T)STRLEN( | 4840 pos.col = (colnr_T)STRLEN( |
4784 ml_get(curwin->w_buffer->b_ml.ml_line_count)); | 4841 ml_get(curwin->w_buffer->b_ml.ml_line_count)); |
4785 } | 4842 } |
4786 } | 4843 } |
4787 p_ws = old_p_ws; | |
4788 } | 4844 } |
4789 | 4845 |
4790 start_pos = pos; | 4846 start_pos = pos; |
4791 p_ws = old_p_ws; | 4847 p_ws = old_p_ws; |
4792 | 4848 |
4795 | 4851 |
4796 // put cursor on last character of match | 4852 // put cursor on last character of match |
4797 curwin->w_cursor = end_pos; | 4853 curwin->w_cursor = end_pos; |
4798 if (LT_POS(VIsual, end_pos)) | 4854 if (LT_POS(VIsual, end_pos)) |
4799 dec_cursor(); | 4855 dec_cursor(); |
4856 else if (VIsual_active && LT_POS(curwin->w_cursor, VIsual)) | |
4857 curwin->w_cursor = pos; // put the cursor on the start of the match | |
4800 VIsual_active = TRUE; | 4858 VIsual_active = TRUE; |
4801 VIsual_mode = 'v'; | 4859 VIsual_mode = 'v'; |
4802 | 4860 |
4803 redraw_curbuf_later(INVERTED); /* update the inversion */ | |
4804 if (*p_sel == 'e') | 4861 if (*p_sel == 'e') |
4805 { | 4862 { |
4806 /* Correction for exclusive selection depends on the direction. */ | 4863 /* Correction for exclusive selection depends on the direction. */ |
4807 if (forward && LTOREQ_POS(VIsual, curwin->w_cursor)) | 4864 if (forward && LTOREQ_POS(VIsual, curwin->w_cursor)) |
4808 inc_cursor(); | 4865 inc_cursor(); |
4824 #endif | 4881 #endif |
4825 redraw_curbuf_later(INVERTED); | 4882 redraw_curbuf_later(INVERTED); |
4826 showmode(); | 4883 showmode(); |
4827 | 4884 |
4828 return OK; | 4885 return OK; |
4829 } | |
4830 | |
4831 /* | |
4832 * Check if the pattern is one character long or zero-width. | |
4833 * If move is TRUE, check from the beginning of the buffer, else from position | |
4834 * "cur". | |
4835 * "direction" is FORWARD or BACKWARD. | |
4836 * Returns TRUE, FALSE or -1 for failure. | |
4837 */ | |
4838 static int | |
4839 is_one_char(char_u *pattern, int move, pos_T *cur, int direction) | |
4840 { | |
4841 regmmatch_T regmatch; | |
4842 int nmatched = 0; | |
4843 int result = -1; | |
4844 pos_T pos; | |
4845 int save_called_emsg = called_emsg; | |
4846 int flag = 0; | |
4847 | |
4848 if (pattern == NULL) | |
4849 pattern = spats[last_idx].pat; | |
4850 | |
4851 if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH, | |
4852 SEARCH_KEEP, ®match) == FAIL) | |
4853 return -1; | |
4854 | |
4855 /* init startcol correctly */ | |
4856 regmatch.startpos[0].col = -1; | |
4857 /* move to match */ | |
4858 if (move) | |
4859 { | |
4860 CLEAR_POS(&pos); | |
4861 } | |
4862 else | |
4863 { | |
4864 pos = *cur; | |
4865 /* accept a match at the cursor position */ | |
4866 flag = SEARCH_START; | |
4867 } | |
4868 | |
4869 if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1, | |
4870 SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) | |
4871 { | |
4872 /* Zero-width pattern should match somewhere, then we can check if | |
4873 * start and end are in the same position. */ | |
4874 called_emsg = FALSE; | |
4875 do | |
4876 { | |
4877 regmatch.startpos[0].col++; | |
4878 nmatched = vim_regexec_multi(®match, curwin, curbuf, | |
4879 pos.lnum, regmatch.startpos[0].col, NULL, NULL); | |
4880 if (nmatched != 0) | |
4881 break; | |
4882 } while (direction == FORWARD ? regmatch.startpos[0].col < pos.col | |
4883 : regmatch.startpos[0].col > pos.col); | |
4884 | |
4885 if (!called_emsg) | |
4886 { | |
4887 result = (nmatched != 0 | |
4888 && regmatch.startpos[0].lnum == regmatch.endpos[0].lnum | |
4889 && regmatch.startpos[0].col == regmatch.endpos[0].col); | |
4890 // one char width | |
4891 if (!result && nmatched != 0 | |
4892 && inc(&pos) >= 0 && pos.col == regmatch.endpos[0].col) | |
4893 result = TRUE; | |
4894 } | |
4895 } | |
4896 | |
4897 called_emsg |= save_called_emsg; | |
4898 vim_regfree(regmatch.regprog); | |
4899 return result; | |
4900 } | 4886 } |
4901 | 4887 |
4902 #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(FEAT_TEXTOBJ) \ | 4888 #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(FEAT_TEXTOBJ) \ |
4903 || defined(PROTO) | 4889 || defined(PROTO) |
4904 /* | 4890 /* |