w3mのNEXT_DOWNをいじってみた

w3mのNEXT_DOWNは、OperaのNavigate downに似ているんだけど、ちょっとだけ違う。w3mは真下にしか移動しないけど、Operaは多少横にずれていても移動してくれる。

というわけで、適当にいじくってみたら、わりと簡単にできた。w3mすごい。
変更したあとのコードはGitHub - mzp/w3m: w3mにおいてあります。そのうち他の変更も加えるかも。

設定項目の追加

fm.hにグローバル変数を追加する。

global int use_lessopen init(FALSE);
global char *keymap_file init(KEYMAP_FILE);

/* 許容する幅を設定する変数 */
global int next_down_width init(10);

rc.cに項目を追加する。これでoをおしたときの設定パネルに項目が追加される。

#define CMT_NEXT_DOWN_WIDTH N_("NEXT_DOWN width")

...
...

struct param_ptr params3[] = {
    ....
    {"next_down_width", P_INT, PI_TEXT, (void *)&next_down_width, 
                        CMT_NEXT_DOWN_WIDTH,
     NULL},
    {NULL, 0, 0, NULL, NULL, NULL},
};

NEXT_DOWNを変更

main.cのnextYをちょっと変更する。多少のx方向を許容するようにする。

static int
max(int x,int y){
  return x > y ? x : y;
}

/* go to the next downward/upward anchor */
static void
nextY(int d)
{
    HmarkerList *hl = Currentbuf->hmarklist;
    Anchor *an, *pan;
    int i, j, x, y, n = searchKeyNum();
    int hseq;

    if (Currentbuf->firstLine == NULL)
	return;
    if (!hl || hl->nmark == 0)
	return;

    an = retrieveCurrentAnchor(Currentbuf);
    if (an == NULL)
	an = retrieveCurrentForm(Currentbuf);

    x = Currentbuf->pos;
    y = Currentbuf->currentLine->linenumber + d;
    pan = NULL;
    hseq = -1;
    for (i = 0; i < n; i++) {
	if (an)
	    hseq = abs(an->hseq);
	an = NULL;
	for (; y >= 0 && y <= Currentbuf->lastLine->linenumber; y += d) {
	  for(j = 0; j < max(next_down_width,1); j++){
	    an = retrieveAnchor(Currentbuf->href, y, x+j);
	    if( !an){
	      an = retrieveAnchor(Currentbuf->formitem, y, x+j);
	    }

	    if(x-j >= 0){
	      if (!an){
		an = retrieveAnchor(Currentbuf->formitem, y, x-j);
	      }
	      if (!an){
		an = retrieveAnchor(Currentbuf->href, y, x-j);
	      }
	    }
	    
	    if (an && hseq != abs(an->hseq)) {
	      pan = an;
	      break;
	    }
	  }
	  if(an){
	    break;
	  }
	}
	if (!an)
	    break;
    }

    if (pan == NULL)
	return;

    gotoLine(Currentbuf, y);
    Currentbuf->pos = pan->start.pos;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

まとめ

これまでの変更をdiffにまとめるとこうなる。

diff --git a/fm.h b/fm.h
index 7ac6b30..057fc7e 100644
--- a/fm.h
+++ b/fm.h
@@ -1143,6 +1143,7 @@ global double image_scale init(100);
 global int use_lessopen init(FALSE);
 
 global char *keymap_file init(KEYMAP_FILE);
+global int next_down_width init(10);
 
 #ifdef USE_M17N
 #define get_mctype(c) ((Lineprop)wtf_type((wc_uchar *)(c)) << 8)
diff --git a/main.c b/main.c
index 17047cf..a24cce8 100644
--- a/main.c
+++ b/main.c
@@ -3776,6 +3776,11 @@ nextX(int d, int dy)
 }
 
 
+static int
+max(int x,int y){
+  return x > y ? x : y;
+}
+
 /* go to the next downward/upward anchor */
 static void
 nextY(int d)
@@ -3803,17 +3808,25 @@ nextY(int d)
 	    hseq = abs(an->hseq);
 	an = NULL;
 	for (; y >= 0 && y <= Currentbuf->lastLine->linenumber; y += d) {
-	  for(j = -10; j < 10; ++j){
-	    if(x+j >= 0) {
-	      an = retrieveAnchor(Currentbuf->href, y, x+j);
+	  for(j = 0; j < max(next_down_width,1); j++){
+	    an = retrieveAnchor(Currentbuf->href, y, x+j);
+	    if( !an){
+	      an = retrieveAnchor(Currentbuf->formitem, y, x+j);
+	    }
+
+	    if(x-j >= 0){
 	      if (!an){
-		an = retrieveAnchor(Currentbuf->formitem, y, x+j);
+		an = retrieveAnchor(Currentbuf->formitem, y, x-j);
 	      }
-	      if (an && hseq != abs(an->hseq)) {
-		pan = an;
-		break;
+	      if (!an){
+		an = retrieveAnchor(Currentbuf->href, y, x-j);
 	      }
 	    }
+	    
+	    if (an && hseq != abs(an->hseq)) {
+	      pan = an;
+	      break;
+	    }
 	  }
 	  if(an){
 	    break;
diff --git a/rc.c b/rc.c
index abb2e31..cceb8e1 100644
--- a/rc.c
+++ b/rc.c
@@ -233,6 +233,8 @@ static int OptionEncode = FALSE;
 
 #define CMT_KEYMAP_FILE N_("keymap file")
 
+#define CMT_NEXT_DOWN_WIDTH N_("NEXT_DOWN width")
+
 #define PI_TEXT    0
 #define PI_ONOFF   1
 #define PI_SEL_C   2
@@ -483,6 +485,8 @@ struct param_ptr params3[] = {
      CMT_PRESERVE_TIMESTAMP, NULL},
     {"keymap_file", P_STRING, PI_TEXT, (void *)&keymap_file, CMT_KEYMAP_FILE,
      NULL},
+    {"next_down_width", P_INT, PI_TEXT, (void *)&next_down_width, CMT_NEXT_DOWN_WIDTH,
+     NULL},
     {NULL, 0, 0, NULL, NULL, NULL},
 };
 
-- 
1.5.5.3