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, &regmatch) == 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(&regmatch, 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, &regmatch) == 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(&regmatch, 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 /*