1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00

'v3.3.4.1'

This commit is contained in:
gnosygnu
2016-03-27 23:44:59 -04:00
parent de67253a9c
commit baaef32df2
903 changed files with 13339 additions and 8695 deletions

View File

@@ -34,15 +34,19 @@ public class Xoa_app_ {
}
}
public static final String Name = "xowa";
public static final String Version = "3.2.1.1";
public static final String Version = "3.3.4.1";
public static String Build_date = "2012-12-30 00:00:00";
public static String Op_sys_str;
public static String User_agent = "";
public static final Gfo_msg_grp Nde = Gfo_msg_grp_.prj_(Name);
public static final Gfo_msg_grp Nde = Gfo_msg_grp_.prj_(Name);
public static Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public static void Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v;} private static Gfo_usr_dlg usr_dlg;
public static Bry_bfr_mkr Utl__bfr_mkr() {return utl__bry_bfr_mkr;} private static final Bry_bfr_mkr utl__bry_bfr_mkr = new Bry_bfr_mkr();
public static Io_stream_zip_mgr Utl__zip_mgr() {return utl__zip_mgr;} private static final Io_stream_zip_mgr utl__zip_mgr = new Io_stream_zip_mgr();
public static Bry_bfr_mkr Utl__bfr_mkr() {return utl__bry_bfr_mkr;} private static final Bry_bfr_mkr utl__bry_bfr_mkr = new Bry_bfr_mkr();
public static Io_stream_zip_mgr Utl__zip_mgr() {return utl__zip_mgr;} private static final Io_stream_zip_mgr utl__zip_mgr = new Io_stream_zip_mgr();
public static Xoa_gfs_mgr Gfs_mgr() {return gfs_mgr;} public static void Gfs_mgr_(Xoa_gfs_mgr v) {gfs_mgr = v;} private static Xoa_gfs_mgr gfs_mgr;
public static void Plog_none(String mod, String fmt) {
String msg = mod + ": " + fmt;
Xoa_app_.Usr_dlg().Plog_many("", "", msg);
}
public static Gfo_usr_dlg usr_dlg_console_() {
Gfo_usr_dlg rv = new Gfo_usr_dlg_base(new Gfo_usr_dlg__log_base(), Gfo_usr_dlg__gui_.Console);
rv.Log_wkr().Queue_enabled_(true);

View File

@@ -25,10 +25,20 @@ import gplx.xowa.wikis.*; import gplx.xowa.wikis.nss.*;
import gplx.xowa.apps.*; import gplx.xowa.files.exts.*;
import gplx.xowa.wikis.domains.*;
public class Xoa_app_fxt {
public static Xoae_app app_() {
public static Xoae_app Make__app__edit() {
Io_mgr.Instance.InitEngine_mem();
Db_conn_bldr.Instance.Reg_default_mem();
return app_("linux", Io_url_.mem_dir_("mem/xowa/"));
return Make__app__edit("linux", Io_url_.mem_dir_("mem/xowa/"));
}
public static Xoae_app Make__app__edit(String op_sys, Io_url root_dir) {
Io_url user_dir = root_dir.GenSubDir_nest("user", "test_user");
Gfo_usr_dlg__log_base.Instance.Log_dir_(user_dir.GenSubDir_nest("tmp", "current"));
Xoae_app app = new Xoae_app(Gfo_usr_dlg_.Test(), Xoa_app_mode.Itm_cmd, root_dir, root_dir.GenSubDir("wiki"), root_dir.GenSubDir("file"), user_dir, root_dir.GenSubDir_nest("user", "anonymous", "wiki"), op_sys);
app.Setup_mgr().Dump_mgr().Data_storage_format_(gplx.core.ios.Io_stream_.Tid_raw); // TEST: set data_storage_format to file, else bldr tests will fails (expects plain text)
GfsCore.Instance.Clear(); // NOTE: must clear
GfsCore.Instance.AddCmd(app, Xoae_app.Invk_app); // NOTE: must add app to GfsCore; app.Gfs_mgr() always adds current app to GfsCore; note this causes old test to leave behind GfsCore for new test
GfsCore.Instance.AddCmd(app, Xoae_app.Invk_xowa); // add alias for app; DATE:2014-06-09
return app;
}
public static Xoav_app Make__app__view() {
Io_mgr.Instance.InitEngine_mem();
@@ -43,16 +53,6 @@ public class Xoa_app_fxt {
rv.Wiki_mgr().Add(new Xowv_wiki(rv, Xow_domain_itm_.Bry__home, user_dir));
return rv;
}
public static Xoae_app app_(String op_sys, Io_url root_dir) {
Io_url user_dir = root_dir.GenSubDir_nest("user", "test_user");
Gfo_usr_dlg__log_base.Instance.Log_dir_(user_dir.GenSubDir_nest("tmp", "current"));
Xoae_app app = new Xoae_app(Gfo_usr_dlg_.Test(), Xoa_app_mode.Itm_cmd, root_dir, root_dir.GenSubDir("wiki"), root_dir.GenSubDir("file"), user_dir, root_dir.GenSubDir_nest("user", "anonymous", "wiki"), op_sys);
app.Setup_mgr().Dump_mgr().Data_storage_format_(gplx.core.ios.Io_stream_.Tid_raw); // TEST: set data_storage_format to file, else bldr tests will fails (expects plain text)
GfsCore.Instance.Clear(); // NOTE: must clear
GfsCore.Instance.AddCmd(app, Xoae_app.Invk_app); // NOTE: must add app to GfsCore; app.Gfs_mgr() always adds current app to GfsCore; note this causes old test to leave behind GfsCore for new test
GfsCore.Instance.AddCmd(app, Xoae_app.Invk_xowa); // add alias for app; DATE:2014-06-09
return app;
}
public static Xowv_wiki Make__wiki__view(Xoa_app app) {return Make__wiki__view(app, "en.wikipedia.org");}
public static Xowv_wiki Make__wiki__view(Xoa_app app, String domain_str) {
byte[] domain_bry = Bry_.new_u8(domain_str);
@@ -61,14 +61,14 @@ public class Xoa_app_fxt {
((Xoav_wiki_mgr)app.Wiki_mgri()).Add(rv);
return rv;
}
public static Xowe_wiki wiki_nonwmf(Xoae_app app, String key) {
public static Xowe_wiki Make__wiki__edit__nonwmf(Xoae_app app, String key) {
Xol_lang_itm lang = new Xol_lang_itm(app.Lang_mgr(), Xol_lang_itm_.Key_en).Kwd_mgr__strx_(true);
Xol_lang_itm_.Lang_init(lang);
return wiki_(app, key, lang);
return Make__wiki__edit(app, key, lang);
}
public static Xowe_wiki wiki_tst_(Xoae_app app) {return wiki_(app, "en.wikipedia.org");}
public static Xowe_wiki wiki_(Xoae_app app, String key) {return wiki_(app, key, app.Lang_mgr().Lang_en());}
public static Xowe_wiki wiki_(Xoae_app app, String key, Xol_lang_itm lang) {
public static Xowe_wiki Make__wiki__edit(Xoae_app app) {return Make__wiki__edit(app, "en.wikipedia.org");}
public static Xowe_wiki Make__wiki__edit(Xoae_app app, String key) {return Make__wiki__edit(app, key, app.Lang_mgr().Lang_en());}
public static Xowe_wiki Make__wiki__edit(Xoae_app app, String key, Xol_lang_itm lang) {
Io_url wiki_dir = app.Fsys_mgr().Wiki_dir().GenSubDir(key);
Xowe_wiki rv = new Xowe_wiki(app, lang, Xow_ns_mgr_.default_(lang.Case_mgr()), Xow_domain_itm_.parse(Bry_.new_u8(key)), wiki_dir);
rv.File_mgr().Dbmeta_mgr().Depth_(2); // TEST: written for 2 depth

View File

@@ -23,12 +23,12 @@ public class Xoa_test_ {
public static boolean Db_skip() {return Bool_.N;}
public static boolean Db_is_mem_dflt() {return Bool_.Y;}
public static void Db_init(Io_url sqlite_url) {Db_init(Db_is_mem_dflt(), sqlite_url);}
public static void Db__init__mem(Xowe_wiki wiki) {
public static void Init__db__edit(Xowe_wiki wiki) {
Db__init__mem();
wiki.Db_mgr_create_as_sql();
wiki.Data__core_mgr().Init_by_make(Xowd_core_db_props.Test, Xob_info_session.Test);
}
public static void Init__db__mem(gplx.xowa.wikis.Xowv_wiki wiki) {
public static void Init__db__view(gplx.xowa.wikis.Xowv_wiki wiki) {
Db__init__mem();
wiki.Init_by_make(Xowd_core_db_props.Test, Xob_info_session.Test);
// wiki.Data__core_mgr().Init_by_make(Xowd_core_db_props.Test, Xob_info_session.Test);
@@ -45,18 +45,6 @@ public class Xoa_test_ {
Db_conn_bldr.Instance.Reg_default_sqlite();
}
}
public static String Db__print_tbl_as_str(Bry_bfr bfr, Db_conn conn, String tbl, String... cols) {
int cols_len = cols.length;
Db_rdr rdr = conn.Stmt_select(tbl, cols).Exec_select__rls_auto();
while (rdr.Move_next()) {
for (int i = 0; i < cols_len; ++i) {
bfr.Add_obj(rdr.Read_at(i));
bfr.Add_byte(i == cols_len - 1 ? Byte_ascii.Nl : Byte_ascii.Pipe);
}
}
rdr.Rls();
return bfr.To_str_and_clear();
}
public static void Inet__init() {
Gfo_inet_conn_.new_prototype_(Gfo_inet_conn_.Tid__mem__hash);
}

View File

@@ -29,7 +29,8 @@ public class Xoa_ttl { // PAGE:en.w:http://en.wikipedia.org/wiki/Help:Link; REF.
public byte[] Raw() {return raw;} private byte[] raw = Bry_.Empty;
public byte[] Wik_txt() {return wik_bgn == -1 ? Bry_.Empty : Bry_.Mid(full_txt, wik_bgn, ns_bgn == -1 ? page_bgn - 1 : ns_bgn - 1);}
public Xow_xwiki_itm Wik_itm() {return wik_itm;} private Xow_xwiki_itm wik_itm;
public byte[] Full_txt() {
public byte[] Full_txt_w_ttl_case() {return Xoa_ttl.Replace_unders(Full_db());}
public byte[] Full_txt_by_orig() {
int bgn = wik_bgn == -1 ? 0 : ns_bgn == -1 ? page_bgn : ns_bgn;
int end = full_txt.length;
if (anch_bgn != -1) end = anch_bgn - 1;
@@ -56,10 +57,10 @@ public class Xoa_ttl { // PAGE:en.w:http://en.wikipedia.org/wiki/Help:Link; REF.
public int Wik_bgn() {return wik_bgn;}
public int Anch_bgn() {return anch_bgn;} // NOTE: anch_bgn is not correct when page has trailing ws; EX: [[A #b]] should have anch_bgn of 3 (1st char after #), but instead it is 2
public byte[] Anch_txt() {return anch_bgn == -1 ? Bry_.Empty : Bry_.Mid(full_txt, anch_bgn, full_txt.length);}
public byte[] Talk_txt() {return ns.Id_is_talk() ? Full_txt() : Bry_.Add(tors_txt, Page_txt());}
public byte[] Subj_txt() {return ns.Id_is_subj() ? Full_txt() : Bry_.Add(tors_txt, Page_txt());}
public byte[] Talk_txt() {return ns.Id_is_talk() ? Full_txt_w_ttl_case() : Bry_.Add(tors_txt, Page_txt());}
public byte[] Subj_txt() {return ns.Id_is_subj() ? Full_txt_w_ttl_case() : Bry_.Add(tors_txt, Page_txt());}
public byte[] Full_url() {return Gfo_url_encoder_.Href.Encode(full_txt);}
public String Full_db_as_str() {return String_.new_u8(Full_db());}
public String Full_db_as_str() {return String_.new_u8(Full_db());}
public byte[] Full_db() {return ns.Gen_ttl(this.Page_db());}
public byte[] Full_db_w_anch() {return Replace_spaces(full_txt);}
public byte[] Page_url() {return Xoa_url_encoder.Instance.Encode(this.Page_txt());}
@@ -103,11 +104,11 @@ public class Xoa_ttl { // PAGE:en.w:http://en.wikipedia.org/wiki/Help:Link; REF.
return new_(wiki, wiki.Appe().Msg_log(), raw, 0, raw.length);
}
public static Xoa_ttl parse(Xowe_wiki wiki, byte[] raw) {return new_(wiki, wiki.Appe().Msg_log(), raw, 0, raw.length);}
private static final Object thread_lock = new Object();
private static final Object thread_lock = new Object();
// $dbkey = preg_replace( '/\xE2\x80[\x8E\x8F\xAA-\xAE]/S', '', $dbkey );
// $dbkey = preg_replace( '/[ _\xA0\x{1680}\x{180E}\x{2000}-\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}]+/u', '_', $dbkey );
private static final int Char__bidi = 1, Char__ws = 2;
private static final Btrie_slim_mgr char_trie = Btrie_slim_mgr.cs()
private static final Btrie_slim_mgr char_trie = Btrie_slim_mgr.cs()
.Add_many_int(Char__bidi , Bry_.New_by_ints(0xE2, 0x80, 0x8E), Bry_.New_by_ints(0xE2, 0x80, 0x8F), Bry_.New_by_ints(0xE2, 0x80, 0xAA), Bry_.New_by_ints(0xE2, 0x80, 0xAB), Bry_.New_by_ints(0xE2, 0x80, 0xAC), Bry_.New_by_ints(0xE2, 0x80, 0xAD), Bry_.New_by_ints(0xE2, 0x80, 0xAE))
.Add_many_int(Char__ws , "\u00A0", "\u1680", "\u180E", "\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006", "\u2007", "\u2008", "\u2009", "\u200A", "\u2028", "\u2029", "\u202F", "\u205F", "\u3000")
;
@@ -386,7 +387,7 @@ public class Xoa_ttl { // PAGE:en.w:http://en.wikipedia.org/wiki/Help:Link; REF.
public static final int Anch_bgn_anchor_only = 1; // signifies lnki which is only anchor; EX: [[#anchor]]
public static final int Max_len = 2048; // ASSUME: max len of 256 * 8 bytes
public static final int Null_wik_bgn = -1;
public static final Xoa_ttl Null = null;
public static final Xoa_ttl Null = null;
}
class Xoa_ttl_trie {
public static Btrie_fast_mgr new_() {

View File

@@ -26,8 +26,8 @@ import gplx.xowa.wikis.nss.*;
import gplx.xowa.wikis.tdbs.hives.*;
public class Xop_fxt {
public Xop_fxt() {
Xoae_app app = Xoa_app_fxt.app_();
wiki = Xoa_app_fxt.wiki_tst_(app);
Xoae_app app = Xoa_app_fxt.Make__app__edit();
wiki = Xoa_app_fxt.Make__wiki__edit(app);
ctor(app, wiki);
}
public Xop_fxt(Xoae_app app, Xowe_wiki wiki) {
@@ -106,7 +106,7 @@ public class Xop_fxt {
public Xop_tblw_th_tkn_chkr tkn_tblw_th_(int bgn, int end) {return (Xop_tblw_th_tkn_chkr)new Xop_tblw_th_tkn_chkr().Src_rng_(bgn, end);}
public Xop_tblw_tr_tkn_chkr tkn_tblw_tr_(int bgn, int end) {return (Xop_tblw_tr_tkn_chkr)new Xop_tblw_tr_tkn_chkr().Src_rng_(bgn, end);}
public Xop_hdr_tkn_chkr tkn_hdr_(int bgn, int end, int hdr_len) {return (Xop_hdr_tkn_chkr)new Xop_hdr_tkn_chkr().Hdr_level_(hdr_len).Src_rng_(bgn, end);}
public Xop_xnde_tkn_chkr tkn_xnde_br_(int pos) {return tkn_xnde_(pos, pos).Xnde_tagId_(Xop_xnde_tag_.Tid_br);}
public Xop_xnde_tkn_chkr tkn_xnde_br_(int pos) {return tkn_xnde_(pos, pos).Xnde_tagId_(Xop_xnde_tag_.Tid__br);}
public Xop_xnde_tkn_chkr tkn_xnde_() {return tkn_xnde_(String_.Pos_neg1, String_.Pos_neg1);}
public Xop_xnde_tkn_chkr tkn_xnde_(int bgn, int end) {return (Xop_xnde_tkn_chkr)new Xop_xnde_tkn_chkr().Src_rng_(bgn, end);}
public Xop_tkn_chkr_base tkn_curly_bgn_(int bgn) {return new Xop_tkn_chkr_base().TypeId_dynamic(Xop_tkn_itm_.Tid_tmpl_curly_bgn).Src_rng_(bgn, bgn + 2);}
@@ -370,6 +370,7 @@ public class Xop_fxt {
public void Test_html_wiki_frag(String raw, String... expd_frags) {Test_str_part_y(Exec_html_wiki(raw), expd_frags);}
public void Test_html_full_frag(String raw, String... expd_frags) {Test_str_part_y(Exec_html_full(raw), expd_frags);}
public void Test_html_full_frag_n(String raw, String... expd_frags) {Test_str_part_n(Exec_html_full(raw), expd_frags);}
public void Test__parse__tmpl_to_html(String raw, String expd) {Test_str_full(raw, gplx.langs.htmls.Gfh_utl.Replace_apos(expd), Exec_html_full(raw));}
public void Test__parse__wtxt_to_html(String raw, String expd) {
String actl = Exec_html_wiki(raw);
Tfds.Eq_str_lines(gplx.langs.htmls.Gfh_utl.Replace_apos(expd), actl, raw);
@@ -427,8 +428,8 @@ public class Xop_fxt {
}
public void Clear_ref_mgr() {this.Page().Ref_mgr().Grps_clear();} // clear to reset count
public static Xop_fxt new_nonwmf() {
Xoae_app app = Xoa_app_fxt.app_();
return new Xop_fxt(app, Xoa_app_fxt.wiki_nonwmf(app, "nethackwiki"));
Xoae_app app = Xoa_app_fxt.Make__app__edit();
return new Xop_fxt(app, Xoa_app_fxt.Make__wiki__edit__nonwmf(app, "nethackwiki"));
}
private final Bry_bfr tmp_bfr = Bry_bfr.new_(255);
public String Exec__parse_to_hdump(String src_str) {

View File

@@ -17,8 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa; import gplx.*;
import gplx.core.primitives.*;
import gplx.xowa.langs.*;
import gplx.xowa.wikis.*; import gplx.xowa.wikis.domains.*; import gplx.xowa.wikis.metas.*; import gplx.xowa.wikis.ttls.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.xwikis.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.cases.*;
import gplx.xowa.wikis.*; import gplx.xowa.wikis.domains.*; import gplx.xowa.wikis.metas.*; import gplx.xowa.wikis.data.site_stats.*; import gplx.xowa.wikis.ttls.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.xwikis.*; import gplx.xowa.addons.*;
import gplx.xowa.files.*; import gplx.xowa.files.repos.*; import gplx.xowa.files.origs.*; import gplx.xowa.files.bins.*; import gplx.fsdb.meta.*; import gplx.fsdb.*;
import gplx.xowa.htmls.*; import gplx.xowa.htmls.core.htmls.utls.*; import gplx.xowa.htmls.core.hzips.*; import gplx.xowa.htmls.core.*; import gplx.xowa.htmls.bridges.dbuis.tbls.*;
import gplx.xowa.parsers.*;
@@ -27,6 +27,7 @@ public interface Xow_wiki extends Xow_ttl_parser, GfoInvkAble {
boolean Type_is_edit();
Xoa_app App();
Xol_lang_itm Lang();
Xol_case_mgr Case_mgr();
byte[] Domain_bry(); // EX: en.wikipedia.org
String Domain_str();
int Domain_tid(); // Xow_domain_tid_.Int__wikipedia
@@ -47,6 +48,8 @@ public interface Xow_wiki extends Xow_ttl_parser, GfoInvkAble {
Xow_mw_parser_mgr Mw_parser_mgr();
Xow_xwiki_mgr Xwiki_mgr();
Xow_wiki_props Props();
Xow_site_stats_mgr Stats();
void Init_by_wiki();
Xoa_url_parser Utl__url_parser();
Xow_url_parser Utl__url_parser();
Xoax_addon_mgr Addon_mgr();
}

View File

@@ -18,13 +18,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package gplx.xowa; import gplx.*;
import gplx.core.brys.*; import gplx.core.primitives.*; import gplx.core.brys.fmtrs.*;
import gplx.xowa.apps.*; import gplx.xowa.apps.fsys.*; import gplx.xowa.apps.cfgs.*; import gplx.xowa.apps.cfgs.gui.*; import gplx.xowa.apps.urls.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*;
import gplx.xowa.wikis.*; import gplx.xowa.wikis.domains.*; import gplx.xowa.wikis.xwikis.*; import gplx.xowa.wikis.nss.*; import gplx.xowa.wikis.metas.*; import gplx.xowa.wikis.ttls.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.wikis.caches.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.xowa.langs.cases.*;
import gplx.xowa.wikis.*; import gplx.xowa.wikis.domains.*; import gplx.xowa.wikis.xwikis.*; import gplx.xowa.wikis.nss.*; import gplx.xowa.wikis.metas.*; import gplx.xowa.wikis.data.site_stats.*; import gplx.xowa.wikis.ttls.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.wikis.caches.*; import gplx.xowa.addons.*;
import gplx.xowa.users.*; import gplx.xowa.htmls.*; import gplx.xowa.users.history.*; import gplx.xowa.specials.*; import gplx.xowa.xtns.*; import gplx.xowa.wikis.dbs.*;
import gplx.xowa.files.*; import gplx.xowa.files.repos.*; import gplx.xowa.files.origs.*; import gplx.xowa.files.bins.*; import gplx.fsdb.*; import gplx.fsdb.meta.*; import gplx.xowa.files.exts.*;
import gplx.xowa.htmls.heads.*; import gplx.xowa.htmls.core.htmls.utls.*; import gplx.xowa.htmls.core.hzips.*; import gplx.xowa.htmls.core.*; import gplx.xowa.htmls.css.*; import gplx.xowa.htmls.ns_files.*; import gplx.xowa.htmls.bridges.dbuis.tbls.*;
import gplx.xowa.bldrs.xmls.*; import gplx.xowa.bldrs.installs.*; import gplx.xowa.bldrs.setups.maints.*;
import gplx.xowa.parsers.*; import gplx.xowa.parsers.utils.*;
import gplx.xowa.wikis.ctgs.*;
import gplx.xowa.guis.views.*;
import gplx.xowa.xtns.gallery.*; import gplx.xowa.xtns.pfuncs.*;
import gplx.xowa.wikis.tdbs.*; import gplx.xowa.wikis.tdbs.hives.*;
@@ -35,7 +36,7 @@ public class Xowe_wiki implements Xow_wiki, GfoInvkAble, GfoEvObj {
this.app = app; this.lang = lang; this.ns_mgr = ns_mgr;
this.domain_itm = domain_itm; this.domain_str = domain_itm.Domain_str(); this.domain_bry = domain_itm.Domain_bry(); this.domain_tid = domain_itm.Domain_type_id(); this.domain_abrv = Xow_abrv_wm_.To_abrv(domain_itm);
this.fsys_mgr = new Xow_fsys_mgr(wiki_dir, app.Fsys_mgr().File_dir().GenSubDir(domain_str));
this.url__parser = new Xoa_url_parser(this);
this.url__parser = new Xow_url_parser(this);
this.xwiki_mgr = new Xow_xwiki_mgr(this);
this.html__hdump_mgr = new Xow_hdump_mgr(this);
this.html_mgr = new Xow_html_mgr(this);
@@ -48,9 +49,9 @@ public class Xowe_wiki implements Xow_wiki, GfoInvkAble, GfoEvObj {
cfg_parser = new Xowc_parser(this);
props.SiteName_(domain_tid).ServerName_(domain_bry);
props.ContentLanguage_(lang.Key_bry());
stats = new Xow_site_stats_mgr(this);
Pf_func_.Reg(lang.Func_regy(), lang);
special_mgr = new Xows_mgr(this, lang);
stats = new Xow_wiki_stats(this);
sys_cfg = new Xow_sys_cfg(this);
hive_mgr = new Xob_hive_mgr(this);
util = new Xow_html_util(this);
@@ -74,20 +75,21 @@ public class Xowe_wiki implements Xow_wiki, GfoInvkAble, GfoEvObj {
cache_mgr = new Xow_cache_mgr(this);
/*if (Bry_.Eq(domain_bry, Xow_domain_itm_.Bry__home))*/ xwiki_mgr.Add_by_atrs(domain_bry, domain_bry); // add full name to xwiki_mgr; needed for lookup in home ns; EX: [[home:Help/Contents]]
}
public GfoEvMgr EvMgr() {return ev_mgr;} private final GfoEvMgr ev_mgr;
public Xow_ns_mgr Ns_mgr() {return ns_mgr;} private final Xow_ns_mgr ns_mgr;
public GfoEvMgr EvMgr() {return ev_mgr;} private final GfoEvMgr ev_mgr;
public Xow_ns_mgr Ns_mgr() {return ns_mgr;} private final Xow_ns_mgr ns_mgr;
public Xoa_ttl Ttl_parse(byte[] ttl) {return Xoa_ttl.parse(this, ttl);}
public Xoa_ttl Ttl_parse(byte[] src, int src_bgn, int src_end) {return Xoa_ttl.new_(this, app.Msg_log(), src, src_bgn, src_end);}
public Xoa_ttl Ttl_parse(int ns_id, byte[] ttl) {return Xoa_ttl.parse(this, ns_id, ttl);}
public boolean Type_is_edit() {return Bool_.Y;}
public Xoa_app App() {return app;}
public Xol_lang_itm Lang() {return lang;} private final Xol_lang_itm lang;
public byte[] Domain_bry() {return domain_bry;} private final byte[] domain_bry;
public String Domain_str() {return domain_str;} private final String domain_str;
public int Domain_tid() {return domain_tid;} private final int domain_tid;
public byte[] Domain_abrv() {return domain_abrv;} private final byte[] domain_abrv;
public Xow_domain_itm Domain_itm() {return domain_itm;} private final Xow_domain_itm domain_itm;
public Xow_fsys_mgr Fsys_mgr() {return fsys_mgr;} private final Xow_fsys_mgr fsys_mgr;
public Xol_lang_itm Lang() {return lang;} private final Xol_lang_itm lang;
public Xol_case_mgr Case_mgr() {return lang.Case_mgr();}
public byte[] Domain_bry() {return domain_bry;} private final byte[] domain_bry;
public String Domain_str() {return domain_str;} private final String domain_str;
public int Domain_tid() {return domain_tid;} private final int domain_tid;
public byte[] Domain_abrv() {return domain_abrv;} private final byte[] domain_abrv;
public Xow_domain_itm Domain_itm() {return domain_itm;} private final Xow_domain_itm domain_itm;
public Xow_fsys_mgr Fsys_mgr() {return fsys_mgr;} private final Xow_fsys_mgr fsys_mgr;
public Xowd_db_mgr Data__core_mgr() {if (db_mgr == null) return null; return db_mgr.Tid() == Xodb_mgr_txt.Tid_txt ? null : this.Db_mgr_as_sql().Core_data_mgr();} // TEST:
public Xof_fsdb_mode File__fsdb_mode() {return file_mgr.Fsdb_mode();}
public Fsdb_db_mgr File__fsdb_core() {return file_mgr.Db_core();}
@@ -98,15 +100,17 @@ public class Xowe_wiki implements Xow_wiki, GfoInvkAble, GfoEvObj {
public boolean Html__hdump_enabled() {return html_mgr__hdump_enabled;} private boolean html_mgr__hdump_enabled = Bool_.N;
public Xoh_page_wtr_mgr Html__wtr_mgr() {return html_mgr.Page_wtr_mgr();}
public boolean Html__css_installing() {return html__css_installing;} public void Html__css_installing_(boolean v) {html__css_installing = v;} private boolean html__css_installing;
public Xoa_url_parser Utl__url_parser() {return url__parser;} private final Xoa_url_parser url__parser;
public Xow_mw_parser_mgr Mw_parser_mgr() {return mw_parser_mgr;} private final Xow_mw_parser_mgr mw_parser_mgr = new Xow_mw_parser_mgr();
public Xow_xwiki_mgr Xwiki_mgr() {return xwiki_mgr;} private final Xow_xwiki_mgr xwiki_mgr;
public Xow_wiki_props Props() {return props;} private final Xow_wiki_props props = new Xow_wiki_props();
public Xow_parser_mgr Parser_mgr() {return parser_mgr;} private final Xow_parser_mgr parser_mgr;
public Xow_url_parser Utl__url_parser() {return url__parser;} private final Xow_url_parser url__parser;
public Xow_mw_parser_mgr Mw_parser_mgr() {return mw_parser_mgr;} private final Xow_mw_parser_mgr mw_parser_mgr = new Xow_mw_parser_mgr();
public Xow_xwiki_mgr Xwiki_mgr() {return xwiki_mgr;} private final Xow_xwiki_mgr xwiki_mgr;
public Xow_wiki_props Props() {return props;} private final Xow_wiki_props props = new Xow_wiki_props();
public Xow_site_stats_mgr Stats() {return stats;} private final Xow_site_stats_mgr stats;
public Xow_parser_mgr Parser_mgr() {return parser_mgr;} private final Xow_parser_mgr parser_mgr;
public Xoax_addon_mgr Addon_mgr() {return addon_mgr;} private final Xoax_addon_mgr addon_mgr = new Xoax_addon_mgr();
public Xow_hdump_mgr Html__hdump_mgr() {return html__hdump_mgr;} private final Xow_hdump_mgr html__hdump_mgr;
public Xow_hdump_mgr Html__hdump_mgr() {return html__hdump_mgr;} private final Xow_hdump_mgr html__hdump_mgr;
public Xoae_app Appe() {return app;} private Xoae_app app;
public Xow_gui_mgr Gui_mgr() {return gui_mgr;} private final Xow_gui_mgr gui_mgr = new Xow_gui_mgr();
public Xow_gui_mgr Gui_mgr() {return gui_mgr;} private final Xow_gui_mgr gui_mgr = new Xow_gui_mgr();
public Xow_user User() {return user;} private Xow_user user = new Xow_user();
public Xow_data_mgr Data_mgr() {return data_mgr;} private Xow_data_mgr data_mgr;
public Xodb_mgr Db_mgr() {return db_mgr;} private Xodb_mgr db_mgr;
@@ -137,8 +141,7 @@ public class Xowe_wiki implements Xow_wiki, GfoInvkAble, GfoEvObj {
public Xow_file_mgr File_mgr() {return file_mgr;} private Xow_file_mgr file_mgr;
public Xow_cfg_wiki_core Cfg_wiki_core() {return cfg_wiki_core;} private Xow_cfg_wiki_core cfg_wiki_core;
public Xob_import_cfg Import_cfg() {return import_cfg;} private Xob_import_cfg import_cfg;
public Xotdb_fsys_mgr Tdb_fsys_mgr() {return tdb_fsys_mgr;} private final Xotdb_fsys_mgr tdb_fsys_mgr;
public Xow_wiki_stats Stats() {return stats;} private Xow_wiki_stats stats;
public Xotdb_fsys_mgr Tdb_fsys_mgr() {return tdb_fsys_mgr;} private final Xotdb_fsys_mgr tdb_fsys_mgr;
public Xou_history_cfg Cfg_history() {return cfg_history;} private Xou_history_cfg cfg_history = new Xou_history_cfg();
public Xoh_cfg_gallery Cfg_gallery() {return cfg_gallery;} private Xoh_cfg_gallery cfg_gallery = new Xoh_cfg_gallery();
public Xoh_file_page_wtr Cfg_file_page() {return cfg_file_page;} private Xoh_file_page_wtr cfg_file_page = new Xoh_file_page_wtr();

View File

@@ -15,7 +15,7 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
public interface Srch_rslt_lnr {
void Notify_rslt_found(Srch_rslt_itm rslt);
package gplx.xowa.addons; import gplx.*; import gplx.xowa.*;
public interface Xoax_addon_itm {
byte[] Addon__key();
}

View File

@@ -0,0 +1,23 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons; import gplx.*; import gplx.xowa.*;
public class Xoax_addon_mgr {
private final Ordered_hash hash = Ordered_hash_.New_bry();
public Xoax_addon_itm Itms__get_or_null(byte[] key) {return (Xoax_addon_itm)hash.Get_by(key);}
public void Itms__add(Xoax_addon_itm itm) {hash.Add(itm.Addon__key(), itm);}
}

View File

@@ -0,0 +1,55 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.ctgs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*;
import gplx.xowa.wikis.data.tbls.*;
public class Xoax_ctg_addon implements Xoax_addon_itm { // TODO:mem_mgr
private final Xow_wiki wiki;
private final Hash_adp_bry hash = Hash_adp_bry.cs();
public Xoax_ctg_addon(Xow_wiki wiki) {this.wiki = wiki;}
public byte[] Addon__key() {return Key_const;} public static final byte[] Key_const = Bry_.new_a7("xowa.category");
public Xoctg_ctg_itm Itms__get_or_null(byte[] key) {return (Xoctg_ctg_itm)hash.Get_by_bry(key);}
public Xoctg_ctg_itm Itms__load(byte[] key) {
Xowd_page_itm tmp_page = new Xowd_page_itm();
wiki.Data__core_mgr().Tbl__page().Select_by_ttl(tmp_page, wiki.Ns_mgr().Ns_category(), key);
gplx.xowa.wikis.data.tbls.Xowd_category_itm itm = wiki.Data__core_mgr().Db__cat_core().Tbl__cat_core().Select(tmp_page.Id());
return Itms__add(key, itm.Count_pages(), itm.Count_subcs(), itm.Count_files());
}
public Xoctg_ctg_itm Itms__add(byte[] key, int pages, int subcs, int files) { // TEST:
Xoctg_ctg_itm rv = new Xoctg_ctg_itm(key, pages, subcs, files);
hash.Add(key, rv);
return rv;
}
/*
public long Mem__size__max() {return mem__size__max;} private long mem__size__max;
public long Mem__size__reduce() {return mem__size__reduce;} private long mem__size__reduce;
public void Mem__free__all() {hash.Clear();}
public void Mem__free__reduce() {Mem_mgr_.Free__reduce(hash);}
public void Mem__free__unused() {Mem_mgr_.Free__unused(hash);}
public long Mem__stat__size() {return mem__stat__size;} private long mem__stat__size;
public long Mem__stat__last() {return mem__stat__last;} private long mem__stat__last;
public int Mem__stat__count() {return mem__stat__count;} private int mem__stat__count;
*/
public static Xoax_ctg_addon Get(Xow_wiki wiki) {
Xoax_ctg_addon rv = (Xoax_ctg_addon)wiki.Addon_mgr().Itms__get_or_null(Key_const);
if (rv == null) {
rv = new Xoax_ctg_addon(wiki);
wiki.Addon_mgr().Itms__add(rv);
}
return rv;
}
}

View File

@@ -0,0 +1,32 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.ctgs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*;
public class Xoctg_ctg_itm {
public Xoctg_ctg_itm(byte[] ttl_wo_ns, int pages, int subcs, int files) {
this.Ttl_wo_ns = ttl_wo_ns;
this.Pages = pages;
this.Subcs = subcs;
this.Files = files;
this.All = pages + subcs + files;
}
public final byte[] Ttl_wo_ns;
public final int Pages;
public final int Subcs;
public final int Files;
public final int All;
}

View File

@@ -15,40 +15,40 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.bldrs.cmds.texts.sqls; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.cmds.*; import gplx.xowa.bldrs.cmds.texts.*;
import gplx.dbs.*;
import gplx.xowa.bldrs.wkrs.*; import gplx.xowa.bldrs.sqls.*;
import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*;
public class Xob_pagelinks_parser_cmd extends Xob_sql_dump_base implements Sql_file_parser_cmd {
private Db_conn core_conn;
private Xowd_pagelinks_temp_tbl temp_tbl;
public Xob_pagelinks_parser_cmd(Xob_bldr bldr, Xowe_wiki wiki) {this.Cmd_ctor(bldr, wiki); this.make_fil_len = Io_mgr.Len_mb;}
@Override public String Sql_file_name() {return "pagelinks";}
@Override public String Cmd_key() {return Xob_cmd_keys.Key_wiki_pagelink;}
private static final byte Fld__pl_from = 0, Fld__pl_namespace = 1, Fld__pl_title = 2;
package gplx.xowa.addons.pagelinks.bldrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.pagelinks.*;
import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.wkrs.*; import gplx.xowa.bldrs.sqls.*;
import gplx.dbs.*; import gplx.dbs.qrys.*; import gplx.xowa.wikis.data.*; import gplx.xowa.addons.pagelinks.dbs.*;
public class Pglnk_bldr_cmd extends Xob_sql_dump_base implements Sql_file_parser_cmd {
private Db_conn conn;
private Pglnk_page_link_temp_tbl temp_tbl;
private int tmp_src_id, tmp_trg_ns;
private int rows = 0;
public Pglnk_bldr_cmd(Xob_bldr bldr, Xowe_wiki wiki) {this.Cmd_ctor(bldr, wiki); this.make_fil_len = Io_mgr.Len_mb;}
@Override public String Sql_file_name() {return Dump_type_key;} public static final String Dump_type_key = "pagelinks";
@Override public String Cmd_key() {return Xob_cmd_keys.Key_wiki_page_link;}
@Override public void Cmd_bgn_hook(Xob_bldr bldr, Sql_file_parser parser) {
parser.Fld_cmd_(this).Flds_req_idx_(4, 0, 1, 2);
wiki.Init_assert();
Xowd_db_file core_db = wiki.Data__core_mgr().Db__core();
this.core_conn = core_db.Conn();
this.temp_tbl = new Xowd_pagelinks_temp_tbl(core_conn);
core_conn.Ddl_delete_tbl(temp_tbl.Tbl_name());
parser.Fld_cmd_(this).Flds_req_idx_(4, 0, 1, 2);
Xob_db_file page_link_db = Xob_db_file.New__page_link(wiki);
this.conn = page_link_db.Conn();
this.temp_tbl = new Pglnk_page_link_temp_tbl(conn);
conn.Meta_tbl_drop(temp_tbl.Tbl_name());
temp_tbl.Create_tbl();
temp_tbl.Insert_bgn();
}
@Override public void Cmd_end() {
if (fail) return;
temp_tbl.Insert_end();
temp_tbl.Create_idx();
Xowd_pagelinks_tbl actl_tbl = new Xowd_pagelinks_tbl(core_conn);
core_conn.Ddl_delete_tbl(actl_tbl.Tbl_name());
Pglnk_page_link_tbl actl_tbl = new Pglnk_page_link_tbl(conn);
conn.Meta_tbl_drop(actl_tbl.Tbl_name());
actl_tbl.Create_tbl();
core_conn.Exec_sql(Sql__pagelinks__make);
core_conn.Ddl_delete_tbl(temp_tbl.Tbl_name());
new Db_attach_mgr(conn, new Db_attach_itm("page_db", wiki.Data__core_mgr().Db__core().Conn()))
.Exec_sql_w_msg("updating page_link", Sql__page_link__make);
conn.Meta_tbl_drop(temp_tbl.Tbl_name());
actl_tbl.Create_idx__src_trg();
actl_tbl.Create_idx__trg_src();
core_conn.Env_vacuum();
conn.Env_vacuum();
}
public void Exec(byte[] src, byte[] fld_key, int fld_idx, int fld_bgn, int fld_end, Bry_bfr file_bfr, Sql_file_parser_data data) {
switch (fld_idx) {
@@ -61,13 +61,14 @@ public class Xob_pagelinks_parser_cmd extends Xob_sql_dump_base implements Sql_f
break;
}
}
private static final String Sql__pagelinks__make = String_.Concat_lines_nl_skip_last
( "INSERT INTO pagelinks (src_id, trg_id, trg_count)"
private static final byte Fld__pl_from = 0, Fld__pl_namespace = 1, Fld__pl_title = 2;
private static final String Sql__page_link__make = String_.Concat_lines_nl_skip_last
( "INSERT INTO page_link (src_id, trg_id, trg_count)"
, "SELECT pl.src_id"
, ", p.page_id"
, ", Count(p.page_id)"
, "FROM pagelinks_temp pl"
, " JOIN page p ON pl.trg_ns = p.page_namespace AND pl.trg_ttl = p.page_title"
, "FROM page_link_temp pl"
, " JOIN <page_db>page p ON pl.trg_ns = p.page_namespace AND pl.trg_ttl = p.page_title"
, "GROUP BY pl.src_id, p.page_id"
);
}

View File

@@ -15,13 +15,13 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.wikis.data.tbls; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*; import gplx.xowa.wikis.data.*;
package gplx.xowa.addons.pagelinks.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.pagelinks.*;
import gplx.core.ios.*; import gplx.dbs.*; import gplx.dbs.qrys.*; import gplx.xowa.wikis.dbs.*; import gplx.dbs.cfgs.*;
public class Xowd_pagelinks_tbl implements Rls_able {
private final String tbl_name = "pagelink"; private final Dbmeta_fld_list flds = Dbmeta_fld_list.new_();
public class Pglnk_page_link_tbl implements Rls_able {
private final String tbl_name = "page_link"; private final Dbmeta_fld_list flds = Dbmeta_fld_list.new_();
private final String fld_src_id, fld_trg_id;
private final Db_conn conn;
public Xowd_pagelinks_tbl(Db_conn conn) {
public Pglnk_page_link_tbl(Db_conn conn) {
this.conn = conn;
fld_src_id = flds.Add_int("src_id");
fld_trg_id = flds.Add_int("trg_id");
@@ -30,8 +30,8 @@ public class Xowd_pagelinks_tbl implements Rls_able {
}
public Db_conn Conn() {return conn;}
public String Tbl_name() {return tbl_name;}
public void Create_tbl() {conn.Ddl_create_tbl(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Create_idx__src_trg() {conn.Ddl_create_idx(Gfo_usr_dlg_.Instance, Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "src_trg", fld_src_id, fld_trg_id));}
public void Create_idx__trg_src() {conn.Ddl_create_idx(Gfo_usr_dlg_.Instance, Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "trg_src", fld_trg_id, fld_src_id));}
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Create_idx__src_trg() {conn.Meta_idx_create(Gfo_usr_dlg_.Instance, Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "src_trg", fld_src_id, fld_trg_id));}
public void Create_idx__trg_src() {conn.Meta_idx_create(Gfo_usr_dlg_.Instance, Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "trg_src", fld_trg_id, fld_src_id));}
public void Rls() {}
}

View File

@@ -15,13 +15,13 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.wikis.data.tbls; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*; import gplx.xowa.wikis.data.*;
package gplx.xowa.addons.pagelinks.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.pagelinks.*;
import gplx.core.ios.*; import gplx.dbs.*; import gplx.dbs.qrys.*; import gplx.xowa.wikis.dbs.*; import gplx.dbs.cfgs.*;
public class Xowd_pagelinks_temp_tbl implements Rls_able {
private final String tbl_name = "pagelinks_temp"; private final Dbmeta_fld_list flds = Dbmeta_fld_list.new_();
public class Pglnk_page_link_temp_tbl implements Rls_able {
private final String tbl_name = "page_link_temp"; private final Dbmeta_fld_list flds = Dbmeta_fld_list.new_();
private final String fld_src_id, fld_trg_ns, fld_trg_ttl;
private final Db_conn conn; private Db_stmt stmt_insert;
public Xowd_pagelinks_temp_tbl(Db_conn conn) {
public Pglnk_page_link_temp_tbl(Db_conn conn) {
this.conn = conn;
flds.Add_int_pkey_autonum("uid");
fld_src_id = flds.Add_int("src_id");
@@ -30,11 +30,11 @@ public class Xowd_pagelinks_temp_tbl implements Rls_able {
conn.Rls_reg(this);
}
public Db_conn Conn() {return conn;}
public String Tbl_name() {return tbl_name;}
public void Create_tbl() {conn.Ddl_create_tbl(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Create_idx() {conn.Ddl_create_idx(Gfo_usr_dlg_.Instance, Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, "main", fld_src_id, fld_trg_ns, fld_trg_ttl));}
public void Insert_bgn() {conn.Txn_bgn("schema__pagelinks__insert"); stmt_insert = conn.Stmt_insert(tbl_name, flds);}
public void Insert_end() {conn.Txn_end(); stmt_insert = Db_stmt_.Rls(stmt_insert);}
public String Tbl_name() {return tbl_name;}
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Create_idx() {conn.Meta_idx_create(Gfo_usr_dlg_.Instance, Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, "main", fld_src_id, fld_trg_ns, fld_trg_ttl));}
public void Insert_bgn() {conn.Txn_bgn("schema__page_link__insert"); stmt_insert = conn.Stmt_insert(tbl_name, flds);}
public void Insert_end() {conn.Txn_end(); stmt_insert = Db_stmt_.Rls(stmt_insert);}
public void Insert(int src_id, int trg_ns, byte[] trg_ttl) {
if (stmt_insert == null) stmt_insert = conn.Stmt_insert(tbl_name, flds);
stmt_insert.Clear().Val_int(fld_src_id, src_id).Val_int(fld_trg_ns, trg_ns).Val_bry_as_str(fld_trg_ttl, trg_ttl).Exec_insert();

View File

@@ -0,0 +1,51 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*;
import gplx.xowa.addons.searchs.dbs.*; import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.parsers.*; import gplx.xowa.addons.searchs.searchers.rslts.*; import gplx.xowa.addons.searchs.searchers.cbks.*;
import gplx.xowa.langs.cases.*;
public class Srch_search_addon implements Xoax_addon_itm {
private final Srch_search_mgr search_mgr;
public Srch_search_addon(Xow_wiki wiki) {
this.wiki_domain = wiki.Domain_bry();
this.db_mgr = new Srch_db_mgr(wiki).Init();
this.ttl_parser = new Srch_text_parser().Init_for_ttl(wiki.Case_mgr());
this.search_mgr = new Srch_search_mgr(this, wiki, ttl_parser);
}
public byte[] Addon__key() {return Key_const;} public static final byte[] Key_const = Bry_.new_a7("xowa.search");
public byte[] Wiki_domain() {return wiki_domain;} private final byte[] wiki_domain;
public Srch_db_mgr Db_mgr() {return db_mgr;} private final Srch_db_mgr db_mgr;
public Srch_text_parser Ttl_parser() {return ttl_parser;} private final Srch_text_parser ttl_parser;
public void Search_cancel() {search_mgr.Search_cancel();}
public void Search(Srch_search_qry qry, Srch_rslt_cbk cbk) {search_mgr.Search(qry, cbk);}
public void Clear_rslts_cache() {search_mgr.Clear_rslts_cache();}
public static final int Score_max = 1000000;
public static final byte Wildcard__star = Byte_ascii.Star;
public static Srch_search_addon Get(Xow_wiki wiki) {
synchronized (wiki.App()) { // THREAD: must synchronized on app, else 2 wikis with simultaneous search commands will get same addon
Srch_search_addon rv = (Srch_search_addon)wiki.Addon_mgr().Itms__get_or_null(Key_const);
if (rv == null) {
Xoa_app_.Usr_dlg().Log_many("", "", "addons.init: ~{0}", Key_const);
rv = new Srch_search_addon(wiki);
wiki.Addon_mgr().Itms__add(rv);
}
return rv;
}
}
}

View File

@@ -0,0 +1,110 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*;
import gplx.core.net.*;
import gplx.xowa.wikis.nss.*;
import gplx.xowa.addons.searchs.searchers.cbks.*; import gplx.xowa.addons.searchs.searchers.*;
public class Srch_search_cfg implements GfoInvkAble {
private final Xoae_app app;
private String args_default_str = "";// default args for search
private byte search_mode = Tid_search_mode_all_pages_v2;
private int all_pages_extend = 1000; // look ahead by 1000
private int all_pages_min = 10000; // only look at pages > 10 kb
private boolean log_enabled = false;
public Srch_search_cfg(Xoae_app app) {
this.app = app;
ns_mgr.Add_main_if_empty();
}
public boolean Enabled() {return enabled;} private boolean enabled = true;
public int Rslts_max() {return results_max;} private int results_max = 25;
public boolean Auto_wildcard() {return auto_wildcard;} private boolean auto_wildcard = false; // automatically add wild-card; EX: Earth -> *Earth*
public Srch_ns_mgr Ns_mgr() {return ns_mgr;} private final Srch_ns_mgr ns_mgr = new Srch_ns_mgr();
public Gfo_qarg_itm[] Args_default() {return args_default;} private Gfo_qarg_itm[] args_default = Gfo_qarg_itm.Ary_empty;
public void Args_default_str_(String v) {
this.args_default_str = v;
byte[] bry = Bry_.new_a7("http://x.org/a?" + v);
Gfo_url tmp_url = new Gfo_url();
app.User().Wikii().Utl__url_parser().Url_parser().Parse(tmp_url, bry, 0, bry.length);
args_default = tmp_url.Qargs();
}
public void Cancel() {if (addon != null) addon.Search_cancel();}
private Srch_search_addon addon;
public void Search(Xowe_wiki wiki, byte[] search_bry, byte[] cbk_func) {
if ( !enabled
|| search_bry.length == 0
) return;
if (addon == null)
addon = Srch_search_addon.Get(wiki);
else {
if (!Bry_.Eq(wiki.Domain_bry(), addon.Wiki_domain())) // NOTE: suggest-box caches addon at wiki level; need to check if wiki has changed
addon = Srch_search_addon.Get(wiki);
}
this.Cancel();
Srch_search_qry qry = Srch_search_qry.New__suggest_box(wiki, this, search_bry);
Srch_rslt_cbk__suggest_box cbk = new Srch_rslt_cbk__suggest_box(wiki.Appe(), cbk_func, search_bry);
addon.Search(qry, cbk);
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_enabled)) return Yn.To_str(enabled);
else if (ctx.Match(k, Invk_enabled_)) enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk_results_max)) return results_max;
else if (ctx.Match(k, Invk_results_max_)) results_max = m.ReadInt("v");
else if (ctx.Match(k, Invk_search_mode)) return Search_mode_str(search_mode);
else if (ctx.Match(k, Invk_search_mode_)) search_mode = Search_mode_parse(m.ReadStr("v"));
else if (ctx.Match(k, Invk_search_mode_list)) return Options_search_mode_list;
else if (ctx.Match(k, Invk_all_pages_extend)) return all_pages_extend;
else if (ctx.Match(k, Invk_all_pages_extend_)) all_pages_extend = m.ReadInt("v");
else if (ctx.Match(k, Invk_all_pages_min)) return all_pages_min;
else if (ctx.Match(k, Invk_all_pages_min_)) all_pages_min = m.ReadInt("v");
else if (ctx.Match(k, Invk_auto_wildcard)) return Yn.To_str(auto_wildcard);
else if (ctx.Match(k, Invk_auto_wildcard_)) auto_wildcard = m.ReadYn("v");
else if (ctx.Match(k, Invk_log_enabled)) return Yn.To_str(log_enabled);
else if (ctx.Match(k, Invk_log_enabled_)) log_enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk_args_default)) return args_default_str;
else if (ctx.Match(k, Invk_args_default_)) Args_default_str_(m.ReadStr("v"));
else return GfoInvkAble_.Rv_unhandled;
return this;
}
public static final String
Invk_enabled = "enabled", Invk_enabled_ = "enabled_", Invk_results_max = "results_max", Invk_results_max_ = "results_max_"
, Invk_search_mode = "search_mode", Invk_search_mode_ = "search_mode_", Invk_search_mode_list = "search_mode_list"
, Invk_all_pages_extend = "all_pages_extend", Invk_all_pages_extend_ = "all_pages_extend_"
, Invk_all_pages_min = "all_pages_min", Invk_all_pages_min_ = "all_pages_min_"
, Invk_auto_wildcard = "auto_wildcard", Invk_auto_wildcard_ = "auto_wildcard_"
, Invk_log_enabled = "log_enabled", Invk_log_enabled_ = "log_enabled_"
, Invk_args_default = "args_default", Invk_args_default_ = "args_default_"
;
private static final String Str_search_mode_search = "Search", Str_search_mode_all_pages_v1 = "AllPages", Str_search_mode_all_pages_v2 = "AllPages_(v2)";
public static final int[] Ns_default_main = new int[] {Xow_ns_.Tid__main};
public static final byte Tid_search_mode_all_pages_v1 = 0, Tid_search_mode_search = 1, Tid_search_mode_all_pages_v2 = 2;
private static Keyval[] Options_search_mode_list = Keyval_.Ary(Keyval_.new_(Str_search_mode_search), Keyval_.new_(Str_search_mode_all_pages_v1), Keyval_.new_(Str_search_mode_all_pages_v2));
private static byte Search_mode_parse(String v) {
if (String_.Eq(v, Str_search_mode_search)) return Tid_search_mode_search;
else if (String_.Eq(v, Str_search_mode_all_pages_v1)) return Tid_search_mode_all_pages_v1;
else if (String_.Eq(v, Str_search_mode_all_pages_v2)) return Tid_search_mode_all_pages_v2;
else throw Err_.new_unhandled(v);
}
private static String Search_mode_str(byte v) {
switch (v) {
case Tid_search_mode_search: return Str_search_mode_search;
case Tid_search_mode_all_pages_v1: return Str_search_mode_all_pages_v1;
case Tid_search_mode_all_pages_v2: return Str_search_mode_all_pages_v2;
default: throw Err_.new_unhandled(v);
}
}
}

View File

@@ -0,0 +1,42 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
public class Srch_db_cfg {
public Srch_db_cfg(int version_id, long page_count, int word_count, int link_count_score_max, int link_count_score_cutoff, int link_score_max) {
this.version_id = version_id;
this.page_count = page_count;
this.word_count = word_count;
this.link_count_score_max = link_count_score_max;
this.link_count_score_cutoff = link_count_score_cutoff;
this.link_score_max = link_score_max;
}
public int Version_id() {return version_id;} private int version_id;
public boolean Version_id__needs_upgrade() {return version_id < Srch_db_upgrade.Version__link_score;}
public long Page_count() {return page_count;} private long page_count;
public int Word_count() {return word_count;} private int word_count;
public int Link_count_score_max() {return link_count_score_max;} private int link_count_score_max;
public int Link_count_score_cutoff() {return link_count_score_cutoff;} private int link_count_score_cutoff;
public int Link_score_max() {return link_score_max;} private int link_score_max;
public void Update_link(int link_score_max) {this.link_score_max = link_score_max;}
public void Update_word(int word_count, int link_count_score_max, int link_count_score_cutoff) {
this.version_id = Srch_db_upgrade.Version__link_score;
this.word_count = word_count;
this.link_count_score_max = link_count_score_max;
this.link_count_score_cutoff = link_count_score_cutoff;
}
}

View File

@@ -0,0 +1,61 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.dbs.cfgs.*;
public class Srch_db_cfg_ {
public static Srch_db_cfg New(Db_cfg_tbl cfg_tbl, long page_count, int version_id) { // NOTE: dflt values are for old search dbs
int word_count = cfg_tbl.Assert_int(Grp__search__cfg, Key__word_count, 0);
int link_count_score_max = cfg_tbl.Assert_int(Grp__search__cfg, Key__link_count_score_max, 0);
int link_count_score_cutoff = cfg_tbl.Assert_int(Grp__search__cfg, Key__link_count_score_cutoff, 0);
int link_score_max = cfg_tbl.Assert_int(Grp__search__cfg, Key__link_score_max, 0);
return new Srch_db_cfg(version_id, page_count, word_count, link_count_score_max, link_count_score_cutoff, link_score_max);
}
public static void Update__bldr__link(Db_cfg_tbl cfg_tbl, Srch_db_cfg cfg, int link_score_max) {
cfg.Update_link(link_score_max);
cfg_tbl.Upsert_int(Grp__search__cfg, Key__link_score_max, link_score_max);
}
public static void Update__bldr__word(Db_cfg_tbl cfg_tbl, Srch_db_cfg cfg, int word_count, int link_count_score_max, int link_count_score_cutoff) {
cfg.Update_word(word_count, link_count_score_max, link_count_score_cutoff);
cfg_tbl.Upsert_int(Grp__search__cfg, Key__version_id, Srch_db_upgrade.Version__link_score);
cfg_tbl.Upsert_int(Grp__search__cfg, Key__word_count, word_count);
cfg_tbl.Upsert_int(Grp__search__cfg, Key__link_count_score_max, link_count_score_max);
cfg_tbl.Upsert_int(Grp__search__cfg, Key__link_count_score_cutoff, link_count_score_cutoff);
}
public static int Select__version_id(Db_cfg_tbl cfg_tbl, Srch_word_tbl word_tbl) {
int rv = cfg_tbl.Select_int_or(Grp__search__cfg, Key__version_id, -1);
if (rv >= Srch_db_upgrade.Version__link_score) return rv; // version_id exists; return it;
if (rv == Srch_db_upgrade.Version__link_score_alpha) { // R.16.03.13 has same schema as later version
rv = Srch_db_upgrade.Version__link_score;
} else {
boolean version_is_page_count = word_tbl.conn.Meta_fld_exists(word_tbl.tbl_name, "word_page_count");
rv = version_is_page_count ? Srch_db_upgrade.Version__page_count : Srch_db_upgrade.Version__initial;
}
cfg_tbl.Upsert_int(Grp__search__cfg, Key__version_id, rv);
return rv;
}
public static final int Link_count_score_cutoff = 300;
private static final String
Grp__search__cfg = "xowa.search.cfg"
, Key__version_id = "version_id"
, Key__word_count = "word_count"
, Key__link_count_score_max = "link_count_score_max"
, Key__link_count_score_cutoff = "link_count_score_cutoff"
, Key__link_score_max = "link_score_max"
;
}

View File

@@ -0,0 +1,114 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.dbs.cfgs.*;
import gplx.xowa.wikis.data.*;
public class Srch_db_mgr {
private final Xow_wiki wiki;
public final Srch_db_upgrade Upgrade_mgr;
public Srch_db_mgr(Xow_wiki wiki) {
this.wiki = wiki;
Upgrade_mgr = new Srch_db_upgrade(wiki, this);
}
public Srch_db_cfg Cfg() {return cfg;} private Srch_db_cfg cfg;
public Db_cfg_tbl Tbl__cfg() {return tbl__cfg;} private Db_cfg_tbl tbl__cfg;
public Srch_word_tbl Tbl__word() {return tbl__word;} private Srch_word_tbl tbl__word;
public int Tbl__link__len() {return tbl__link__ary.length;}
public Srch_link_tbl Tbl__link__get_at(int i) {return tbl__link__ary[i];}
public Srch_link_tbl[] Tbl__link__ary() {return tbl__link__ary;} private Srch_link_tbl[] tbl__link__ary = Srch_link_tbl.Ary_empty;
public Srch_db_mgr Init() {
Xowd_db_mgr db_mgr = wiki.Data__core_mgr();
Xowd_db_file word_db = null;
if (db_mgr.Db__core().Db_props().Layout_text().Tid_is_all_or_few()) {
// single_db; core_db has search_word and search_link
word_db = db_mgr.Db__core();
tbl__cfg = new Db_cfg_tbl(word_db.Conn(), "xowa_cfg");
tbl__word = new Srch_word_tbl(word_db.Conn(), word_db.Db_props().Schema_is_1());
tbl__link__ary = new Srch_link_tbl[1];
Tbl__link__ary__set(tbl__link__ary, 0, word_db);
} else {
// many_db; figure out link_dbs
word_db = db_mgr.Dbs__get_by_tid_or_null(Srch_db_mgr_.Dbtid__search_core);
if (word_db == null) return this; // HACK: called during db build; skip;
tbl__cfg = new Db_cfg_tbl(word_db.Conn(), "xowa_cfg");
tbl__word = new Srch_word_tbl(word_db.Conn(), word_db.Db_props().Schema_is_1());
Ordered_hash hash = db_mgr.Dbs__get_hash_by_tid(Srch_db_mgr_.Dbtid__search_link);
if (hash == null) { // v2 file layout where search_word and search_link is in 1 search_db
tbl__link__ary = new Srch_link_tbl[1];
Tbl__link__ary__set(tbl__link__ary, 0, word_db);
} else { // v3 file layout where search_link is in many db
int dbs_len = hash.Count();
tbl__link__ary = new Srch_link_tbl[dbs_len];
for (int i = 0; i < dbs_len; ++i) {
Xowd_db_file db_file = (Xowd_db_file)hash.Get_at(i);
Tbl__link__ary__set(tbl__link__ary, i, db_file);
}
}
}
cfg = Srch_db_cfg_.New(tbl__cfg, wiki.Stats().Num_pages(), Srch_db_cfg_.Select__version_id(tbl__cfg, tbl__word));
return this;
}
public void Delete_all(Xowd_db_mgr core_data_mgr) {
tbl__word.conn.Meta_tbl_drop(Srch_link_reg_tbl.Tbl_name);
if (wiki.Data__core_mgr().Db__core().Db_props().Layout_text().Tid_is_all_or_few()) {
// single_db; just drop tables
tbl__word.conn.Meta_tbl_drop(tbl__word.tbl_name);
Srch_link_tbl link_tbl = tbl__link__ary[0];
link_tbl.conn.Meta_tbl_drop(link_tbl.tbl_name);
} else {
// many_db; drop databases
core_data_mgr.Dbs__delete_by_tid(Xowd_db_file_.Tid_search_core);
core_data_mgr.Dbs__delete_by_tid(Xowd_db_file_.Tid_search_link);
}
}
public void Create_all() {
Xowd_db_mgr db_mgr = wiki.Data__core_mgr();
if (wiki.Data__core_mgr().Db__core().Db_props().Layout_text().Tid_is_all_or_few()) {
// single_db; put both in core_db
Xowd_db_file search_db = db_mgr.Db__core();
tbl__word = new Srch_word_tbl(search_db.Conn(), Bool_.N); tbl__word.Create_tbl();
Srch_link_tbl tbl__link = new Srch_link_tbl(search_db.Conn(), Bool_.N); tbl__link.Create_tbl();
tbl__link__ary = new Srch_link_tbl[] {tbl__link};
Srch_link_reg_tbl tbl__lreg = new Srch_link_reg_tbl(search_db.Conn()); tbl__lreg.Create_tbl();
Tbl__link__ary__new(tbl__lreg, tbl__link__ary, db_mgr, 0, Bool_.N, search_db);
} else {
// many_db: put in 3 db;
Xowd_db_file word_db = db_mgr.Dbs__make_by_tid(Srch_db_mgr_.Dbtid__search_core);
tbl__word = new Srch_word_tbl(word_db.Conn(), Bool_.N); tbl__word.Create_tbl();
tbl__link__ary = new Srch_link_tbl[2];
Srch_link_reg_tbl tbl__lreg = new Srch_link_reg_tbl(word_db.Conn()); tbl__lreg.Create_tbl();
Tbl__link__ary__new(tbl__lreg, tbl__link__ary, db_mgr, 0, Bool_.Y, null);
Tbl__link__ary__new(tbl__lreg, tbl__link__ary, db_mgr, 1, Bool_.N, null);
}
}
private static Srch_link_tbl Tbl__link__ary__set(Srch_link_tbl[] ary, int idx, Xowd_db_file db) {
Srch_link_tbl tbl = new Srch_link_tbl(db.Conn(), db.Db_props().Schema_is_1());
ary[idx] = tbl;
return tbl;
}
private static void Tbl__link__ary__new(Srch_link_reg_tbl lreg_tbl, Srch_link_tbl[] ary, Xowd_db_mgr db_mgr, int idx, boolean ns_ids_is_main, Xowd_db_file db) {
if (db == null) {
String ns_ids = (ns_ids_is_main ? "000" : "999");
String suffix = "-xtn.search.link-title-ns." + ns_ids + "-db.001.xowa"; // -xtn.search.link-title-ns.main-db.001.xowa
db = db_mgr.Dbs__make_by_tid(Srch_db_mgr_.Dbtid__search_link, ns_ids, idx, suffix);
}
Srch_link_tbl tbl = Tbl__link__ary__set(ary, idx, db);
tbl.Create_tbl();
lreg_tbl.Insert(idx, db.Id(), Srch_link_reg_tbl.Db_type__title, ns_ids_is_main ? Srch_link_reg_tbl.Ns_type__main : Srch_link_reg_tbl.Ns_type__rest, 0, -1, -1);
}
}

View File

@@ -15,7 +15,8 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
public interface Xosrh_page_mgr_searcher {
List_adp Parse_search_and_load_ids(Cancelable cancelable, Bry_bfr bfr, Xows_ns_mgr ns_Mgr, byte[] search);
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.xowa.wikis.data.*;
public class Srch_db_mgr_ {
public static final byte Dbtid__search_core = 4, Dbtid__search_link = 16; // SYNC:Xowd_db_file_
}

View File

@@ -0,0 +1,55 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.dbs.*; import gplx.dbs.cfgs.*;
public class Srch_db_upgrade {
private final Xow_wiki wiki;
private boolean upgrade_prompted;
public Srch_db_upgrade(Xow_wiki wiki, Srch_db_mgr search_db_mgr) {
this.wiki = wiki;
}
public void Upgrade() {
if (!wiki.App().Mode().Tid_is_gui()) return; // ignore if html-server or drd-app
if (upgrade_prompted) return;
upgrade_prompted = true;
Xoae_app app = ((Xoae_app)wiki.App());
boolean ok = app.Gui_mgr().Kit().Ask_ok_cancel("", "", String_.Concat_lines_nl_skip_last
( "XOWA would like to upgrade your search database for " + wiki.Domain_str() + "."
, ""
, "* Press OK to upgrade. This may take an hour for English Wikipedia."
, "* Press Cancel to skip. You will not be able to search."
, ""
, "If you cancel, XOWA will ask you to upgrade this wiki again next time you restart the application."
, ""
, "Note that you can run this upgrade process manually by doing:"
, " Main Menu -> Tools -> Wiki Maintenance -> Search"
));
if (!ok) return;
Xowe_wiki wikie = (Xowe_wiki)wiki;
gplx.xowa.addons.searchs.dbs.bldrs.Srch_bldr_mgr_.Setup(wikie);
gplx.xowa.bldrs.Xob_bldr bldr = app.Bldr();
bldr.Cmd_mgr().Add(new gplx.xowa.bldrs.cmds.utils.Xob_alert_cmd(bldr, wikie).Msg_("search upgrade finished"));
gplx.core.threads.Thread_adp_.invk_("search_upgrade", app.Bldr(), gplx.xowa.bldrs.Xob_bldr.Invk_run).Start();
}
public static final int
Version__link_score_alpha = 0 // in 2016-02 android alpha
, Version__initial = 1
, Version__page_count = 2
, Version__link_score = 3
;
}

View File

@@ -0,0 +1,44 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.dbs.*;
public class Srch_link_reg_tbl implements Rls_able {
private final String tbl_name; public final Dbmeta_fld_list flds = Dbmeta_fld_list.new_();
private final String fld_id, fld_db_id, fld_db_type, fld_ns_ids, fld_sub_id, fld_score_min, fld_score_max;
private final Db_conn conn;
public Srch_link_reg_tbl(Db_conn conn) {
this.conn = conn;
tbl_name = Tbl_name;
fld_id = flds.Add_int_pkey ("reg_id"); // corresponds to link_tbl_ary_idx
fld_db_id = flds.Add_int ("reg_db_id"); // corresponds to xowa_db
fld_db_type = flds.Add_int ("reg_db_type"); // "title"; "text"
fld_ns_ids = flds.Add_int ("reg_ns_ids"); // "0"; "*"
fld_sub_id = flds.Add_int ("reg_sub_id"); // "0"; "*"
fld_score_min = flds.Add_int ("reg_score_min"); // -1
fld_score_max = flds.Add_int ("reg_score_max"); // -1
}
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Rls() {}
public void Insert(int id, int db_id, String db_type, String ns_ids, int sub_id, int score_min, int score_max) {
Db_stmt stmt_insert = conn.Stmt_insert(tbl_name, flds);
stmt_insert.Clear().Val_int(fld_id, id).Val_int(fld_db_id, db_id).Val_str(fld_db_type, db_type).Val_str(fld_ns_ids, ns_ids).Val_int(fld_sub_id, sub_id).Val_int(fld_score_min, score_min).Val_int(fld_score_max, score_max).Exec_insert();
}
public static final String Tbl_name = "search_link_reg";
public static final String Db_type__title = "title" , Db_type__text = "text";
public static final String Ns_type__main = "0" , Ns_type__rest = "*";
}

View File

@@ -0,0 +1,41 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.dbs.*;
public class Srch_link_tbl {
public final String tbl_name;
public final Dbmeta_fld_list flds = Dbmeta_fld_list.new_();
public final String fld_word_id, fld_page_id, fld_link_score;
public final boolean schema_is_1;
public final Db_conn conn;
public Srch_link_tbl(Db_conn conn, boolean schema_is_1) {
this.conn = conn; this.schema_is_1 = schema_is_1;
String fld_prefix = "";
if (schema_is_1) {tbl_name = "search_title_page"; fld_prefix = "stp_";}
else {tbl_name = "search_link";}
fld_word_id = flds.Add_int(fld_prefix + "word_id");
fld_page_id = flds.Add_int(fld_prefix + "page_id");
fld_link_score = flds.Add_int_dflt(fld_prefix + Fld_link_score, 0);
}
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Create_idx__page_id() {} // TODO: conn.Meta_idx_create(Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, "page_id", fld_page_id));}
public void Create_idx__link_score() {conn.Meta_idx_create(Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, "word_id__link_score", fld_word_id, Fld_link_score));}
public static final Srch_link_tbl[] Ary_empty = new Srch_link_tbl[0];
public static final String Fld_link_score = "link_score";
}

View File

@@ -0,0 +1,45 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.dbs.*;
public class Srch_temp_tbl {
public final String tbl_name = "search_temp";
private final Dbmeta_fld_list flds = Dbmeta_fld_list.new_();
private final String fld_word_id, fld_page_id, fld_word_text;
public final Db_conn conn; private Db_stmt stmt_insert;
public Srch_temp_tbl(Db_conn conn) {
this.conn = conn;
flds.Add_int_pkey_autonum("word_uid");
fld_word_id = flds.Add_int("word_id");
fld_page_id = flds.Add_int("page_id");
fld_word_text = flds.Add_str("word_text", 255);
}
public void Insert_bgn() {
conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));
stmt_insert = conn.Stmt_insert(tbl_name, flds);
conn.Txn_bgn("schema__search_temp__insert");
}
public void Insert_cmd_by_batch(int word_id, int page_id, byte[] word) {
stmt_insert.Clear().Val_int(fld_word_id, word_id).Val_int(fld_page_id, page_id).Val_bry_as_str(fld_word_text, word).Exec_insert();
}
public void Insert_end() {
conn.Txn_end();
stmt_insert = Db_stmt_.Rls(stmt_insert);
conn.Meta_idx_create(Xoa_app_.Usr_dlg(), Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "main", fld_word_text, fld_page_id));
}
}

View File

@@ -15,23 +15,17 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
class Srch_crt_tkn {
public final byte tid;
public final byte[] val;
public Srch_crt_tkn(byte tid, byte[] val) {this.tid = tid; this.val = val;}
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
public class Srch_word_row {
public Srch_word_row(int id, byte[] text, int link_count, int link_score_min, int link_score_max) {
this.Id = id; this.Text = text; this.Link_count = link_count;
this.Link_score_min = link_score_min; this.Link_score_max = link_score_max;
}
public final int Id;
public final byte[] Text;
public final int Link_count;
public final int Link_score_min;
public final int Link_score_max;
public static final byte
Tid_root = 1
, Tid_word = 2
, Tid_word_quoted = 3
, Tid_space = 4
, Tid_quote = 5
, Tid_not = 6
, Tid_paren_bgn = 7
, Tid_paren_end = 8
, Tid_or = 9
, Tid_and = 10
, Tid_eos = 11
;
public static final Srch_word_row Empty = new Srch_word_row(-1, Bry_.Empty, 0, 0, 0);
}

View File

@@ -0,0 +1,66 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.dbs.*;
public class Srch_word_tbl implements Rls_able {
public final String tbl_name;
public final Dbmeta_fld_list flds = Dbmeta_fld_list.new_();
public final String fld_id, fld_text, fld_link_count, fld_link_count_score, fld_link_score_min, fld_link_score_max;
public final Db_conn conn; private Db_stmt stmt_insert, stmt_select_by;
public Srch_word_tbl(Db_conn conn, boolean schema_is_1) {
this.conn = conn;
String fld_prefix = "", fld_text_name = "word_text";
if (schema_is_1) {tbl_name = "search_title_word"; fld_prefix = "stw_"; fld_text_name = "stw_word";}
else {tbl_name = "search_word";}
this.fld_id = flds.Add_int_pkey(fld_prefix + "word_id");
this.fld_text = flds.Add_str(fld_text_name, 255);
this.fld_link_count = flds.Add_int("link_count");
this.fld_link_count_score = Dbmeta_fld_itm.Make_or_null(conn, flds, tbl_name, Dbmeta_fld_tid.Tid__int, 0, "link_count_score");
this.fld_link_score_min = Dbmeta_fld_itm.Make_or_null(conn, flds, tbl_name, Dbmeta_fld_tid.Tid__int, Int_.Max_value__31, "link_score_min");
this.fld_link_score_max = Dbmeta_fld_itm.Make_or_null(conn, flds, tbl_name, Dbmeta_fld_tid.Tid__int, 0, "link_score_max");
conn.Rls_reg(this);
}
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Create_idx() {
// idx for rng_bgn, rng_end
conn.Meta_idx_create(Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, "word_text__link_score_max__link_score_min", fld_text, Fld_link_score_max, Fld_link_score_min));
// idx for like
conn.Meta_idx_create(Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, "link_score_max__link_score_min", Fld_link_score_max, Fld_link_score_min));
}
public void Insert_bgn() {conn.Txn_bgn("schema__search_word__insert"); stmt_insert = conn.Stmt_insert(tbl_name, flds);}
public void Insert_end() {conn.Txn_end(); stmt_insert = Db_stmt_.Rls(stmt_insert);}
public void Insert_cmd_by_batch(int id, byte[] word, int page_count) {stmt_insert.Clear().Val_int(fld_id, id).Val_bry_as_str(fld_text, word).Val_int(fld_link_count, page_count).Exec_insert();}
public Srch_word_row Select_or_empty(byte[] word) {
if (stmt_select_by == null) stmt_select_by = conn.Stmt_select(tbl_name, flds, fld_text);
Db_rdr rdr = stmt_select_by.Clear().Crt_bry_as_str(fld_text, word).Exec_select__rls_manual();
try {return rdr.Move_next() ? New_row(rdr) : Srch_word_row.Empty;}
finally {rdr.Rls();}
}
public Srch_word_row New_row(Db_rdr rdr) {
int page_count = fld_link_count == Dbmeta_fld_itm.Key_null ? 0 : rdr.Read_int(fld_link_count);
int link_score_min = fld_link_score_min == Dbmeta_fld_itm.Key_null ? page_count : rdr.Read_int(fld_link_score_min);
int link_score_max = fld_link_score_max == Dbmeta_fld_itm.Key_null ? page_count : rdr.Read_int(fld_link_score_max);
return new Srch_word_row(rdr.Read_int(fld_id), rdr.Read_bry_by_str(fld_text), page_count, link_score_min, link_score_max);
}
public void Rls() {
stmt_insert = Db_stmt_.Rls(stmt_insert);
stmt_select_by = Db_stmt_.Rls(stmt_select_by);
}
public static final String Fld_link_score_min = "link_score_min", Fld_link_score_max = "link_score_max";
}

View File

@@ -0,0 +1,34 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs.bldrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.dbs.*;
import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.wkrs.*;
public class Srch_bldr_cmd extends Xob_cmd__base implements Xob_cmd {
private int commit_interval = 100000, progress_interval = 10000;
public Srch_bldr_cmd(Xob_bldr bldr, Xowe_wiki wiki) {super(bldr, wiki);}
@Override public String Cmd_key() {return Xob_cmd_keys.Key_text_search_cmd;}
@Override public void Cmd_run() {
if (!gplx.core.envs.Env_.Mode_testing()) wiki.Init_assert();
new Srch_temp_tbl_wkr().Exec_by_cmd(wiki, commit_interval, progress_interval);
}
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_commit_interval_)) commit_interval = m.ReadInt("v");
else if (ctx.Match(k, Invk_progress_interval_)) progress_interval = m.ReadInt("v");
else return GfoInvkAble_.Rv_unhandled;
return this;
} private static final String Invk_progress_interval_ = "progress_interval_", Invk_commit_interval_ = "commit_interval_";
}

View File

@@ -0,0 +1,38 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs.bldrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.dbs.*;
import gplx.xowa.bldrs.*;
import gplx.xowa.addons.searchs.dbs.bldrs.cmds.*;
public class Srch_bldr_mgr_ {
public static void Setup(Xowe_wiki wiki) {
Xoae_app app = wiki.Appe();
Xob_bldr bldr = app.Bldr();
bldr.Cmd_mgr().Add_many(wiki, Xob_cmd_keys.Key_text_search_cmd);
int page_rank_iterations = app.Api_root().Bldr().Wiki().Import().Page_rank().Iteration_max();
boolean page_rank_enabled = page_rank_iterations > 0;
if (page_rank_enabled) {
bldr.Cmd_mgr().Add(new gplx.xowa.bldrs.cmds.utils.Xob_download_cmd(bldr, wiki).Dump_type_(gplx.xowa.addons.pagelinks.bldrs.Pglnk_bldr_cmd.Dump_type_key));
bldr.Cmd_mgr().Add_many(wiki, Xob_cmd_keys.Key_wiki_page_link);
}
bldr.Cmd_mgr().Add(new Srch__page__page_score(bldr, wiki).Iteration_max_(page_rank_iterations));
bldr.Cmd_mgr().Add(new Srch__link__link_score(bldr, wiki).Page_rank_enabled_(page_rank_enabled).Delete_plink_db_(Bool_.Y));
bldr.Cmd_mgr().Add(new Srch__word__link_count(bldr, wiki));
bldr.Cmd_mgr().Add(new gplx.xowa.bldrs.cmds.utils.Xob_delete_cmd(bldr, wiki).Patterns_ary_("*pagelinks.sql", "*pagelinks.sql.gz", "*pagelinks.sqlite3"));
}
}

View File

@@ -0,0 +1,36 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs.bldrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.dbs.*;
import gplx.xowa.bldrs.*;
public class Srch_bldr_wkr implements Xob_page_wkr {
private final Xowe_wiki wiki;
private final Srch_temp_tbl_wkr temp_tbl_wkr = new Srch_temp_tbl_wkr();
public Srch_bldr_wkr(Xob_bldr bldr, Xowe_wiki wiki) {this.wiki = wiki;}
public String Wkr_key() {return Xob_cmd_keys.Key_text_search_wkr;}
public void Wkr_bgn(Xob_bldr bldr) {
temp_tbl_wkr.Init(Bool_.N, wiki);
}
public void Wkr_run(gplx.xowa.wikis.data.tbls.Xowd_page_itm page) {
try {temp_tbl_wkr.Exec_by_wkr(page.Id(), page.Ttl_page_db());}
catch (Exception e) {Gfo_usr_dlg_.Instance.Warn_many("", "", "search:error: page=~{0} err=~{1}", page.Ttl_page_db(), Err_.Message_gplx_full(e));}
}
public void Wkr_end() {
temp_tbl_wkr.Term();
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;}
}

View File

@@ -0,0 +1,171 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs.bldrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.dbs.*;
import gplx.dbs.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.addons.searchs.dbs.*; import gplx.xowa.addons.searchs.parsers.*;
class Srch_temp_tbl_wkr implements Srch_text_parser_wkr {
private Xowe_wiki wiki; private Xowd_db_mgr core_data_mgr; private Srch_search_addon search_addon;
private Srch_text_parser title_parser;
private Srch_temp_tbl search_temp_tbl; private int word_id, page_id; // needed for Parse_done
public Srch_temp_tbl_wkr Init(boolean cmd, Xowe_wiki wiki) {
// init
this.wiki = wiki;
this.core_data_mgr = wiki.Db_mgr_as_sql().Core_data_mgr();
this.search_addon = Srch_search_addon.Get(wiki);
this.title_parser = search_addon.Ttl_parser();
this.word_id = 0;
// assert search_word / search_link tables
Srch_db_mgr search_db_mgr = search_addon.Db_mgr();
if (cmd) search_db_mgr.Delete_all(core_data_mgr); // always delete if launched by cmd
search_db_mgr.Create_all();
// start processing search_temp
this.search_temp_tbl = new Srch_temp_tbl(search_db_mgr.Tbl__word().conn);
search_temp_tbl.Insert_bgn();
return this;
}
public void Term() {
// end inserts
search_temp_tbl.Insert_end();
// init
Srch_db_mgr search_db_mgr = search_addon.Db_mgr();
Db_conn word_conn = search_temp_tbl.conn;
Db_conn page_conn = wiki.Data__core_mgr().Tbl__page().conn;
// update search_word ids if they exist
Update_word_id(word_conn, wiki);
word_conn.Exec_sql("filling search_word (please wait)", Sql__create_word);
// create search_link
if (search_db_mgr.Tbl__link__len() == 1) {
// single_db; just run sql;
Srch_link_tbl link_tbl = search_db_mgr.Tbl__link__ary()[0];
new Db_attach_mgr(word_conn, new Db_attach_itm("link_db", link_tbl.conn))
.Exec_sql(Sql__create_link__one);
link_tbl.Create_idx__page_id();
} else {
// many_db; split into main links and non-main; ASSUME:link_dbs_is_2
int len = search_db_mgr.Tbl__link__len();
Db_attach_mgr attach_mgr = new Db_attach_mgr();
for (int i = 0; i < len; ++i) {
Srch_link_tbl link_tbl = search_db_mgr.Tbl__link__ary()[i];
attach_mgr.Main_conn_(word_conn).Init
( new Db_attach_itm("page_db", page_conn)
, new Db_attach_itm("link_db", link_tbl.conn));
attach_mgr.Exec_sql(Sql__create_link__many, i == 0 ? " = 0" : " != 0");
link_tbl.Create_idx__page_id();
}
}
// remove search_temp
word_conn.Meta_tbl_drop(search_temp_tbl.tbl_name);
}
public void Exec_by_wkr(int page_id, byte[] page_ttl) {
this.page_id = page_id;
title_parser.Parse(this, page_ttl);
}
public void Exec_by_cmd(Xowe_wiki wiki, int commit_interval, int progress_interval) {
this.Init(Bool_.Y, wiki);
Xowd_page_tbl page_tbl = core_data_mgr.Tbl__page(); String fld_page_id = page_tbl.Fld_page_id(); String fld_page_ttl = page_tbl.Fld_page_title();
Db_rdr page_rdr = page_tbl.Select_all__id__ttl(); int page_count = 0;
try {
while (page_rdr.Move_next()) {
this.page_id = page_rdr.Read_int(fld_page_id);
byte[] page_ttl = page_rdr.Read_bry_by_str(fld_page_ttl);
try {title_parser.Parse(this, page_ttl);}
catch (Exception e) {Xoa_app_.Usr_dlg().Warn_many("", "", "error while parsing title; id=~{0} title=~{1} err=~{2}", page_id, page_ttl, Err_.Message_gplx_log(e));}
++page_count;
if ((page_count % commit_interval) == 0) search_temp_tbl.conn.Txn_sav();
if ((page_count % progress_interval) == 0) Gfo_usr_dlg_.Instance.Prog_many("", "", "parse progress: count=~{0} last=~{1}", page_count, String_.new_u8(page_ttl));
}
} finally {page_rdr.Rls();}
this.Term();
}
public void Parse_done(Srch_word_itm word) {
search_temp_tbl.Insert_cmd_by_batch(++word_id, page_id, word.Word);
}
private void Update_word_id(Db_conn cur_conn, Xow_wiki wiki) {
// see if prv_url exists
Io_url cur_url = gplx.dbs.engines.sqlite.Sqlite_conn_info.To_url(cur_conn); // EX: /xowa/wiki/en.wikipedia.org/en.wikipedia.org-xtn.search.core.xowa
Io_url prv_url = wiki.Fsys_mgr().Root_dir().GenSubFil_nest("prv", cur_url.NameAndExt()); // EX: /xowa/wiki/en.wikipedia.org/prv/en.wikipedia.org-xtn.search.core.xowa
if (!Io_mgr.Instance.Exists(prv_url)) return;
// update ids for old_words
cur_conn.Exec_sql("UPDATE search_temp SET word_id = -1");
Db_conn prv_conn = Db_conn_bldr.Instance.Get_or_noop(prv_url);
new Db_attach_mgr(cur_conn, new Db_attach_itm("prv_db", prv_conn))
.Exec_sql_w_msg("updating old word ids", String_.Concat_lines_nl_skip_last
( "UPDATE search_temp"
, "SET word_id = Coalesce((SELECT prv.word_id FROM <prv_db>search_word prv WHERE prv.word_text = search_temp.word_text), -1)"
));
// assign incrementing int to new_words
int nxt_word_id = cur_conn.Exec_select_as_int("SELECT Max(word_id) AS word_id FROM search_temp", -1); if (nxt_word_id == -1) throw Err_.new_("dbs", "max_id not found");
int uids_max = 10000;
int[] uids_ary = new int[uids_max]; int uid_last = -1;
Db_stmt update_stmt = cur_conn.Stmt_update("search_temp", String_.Ary("word_uid"), "word_id");
while (true) {
// read 10,000 into memory
int uids_len = 0;
Db_rdr rdr = cur_conn.Exec_rdr("SELECT word_uid FROM search_temp WHERE word_id = -1 AND word_uid > " + Int_.To_str(uid_last));
try {
while (rdr.Move_next()) {
int uid = rdr.Read_int("word_uid");
uids_ary[uids_len++] = uid;
if (uids_len == uids_max) {
uid_last = uid;
break;
}
}
}
finally {rdr.Rls();}
if (uids_len == 0) break;
// update
for (int i = 0; i < uids_max; ++i) {
int uid = uids_ary[i];
update_stmt.Clear().Val_int("word_id", ++nxt_word_id).Crt_int("word_uid", uid).Exec_update();
}
}
}
private static final String
Sql__create_word = String_.Concat_lines_nl
( "INSERT INTO search_word (word_id, word_text, link_count)"
, "SELECT word_id"
, ", word_text"
, ", Count(DISTINCT page_id)"
, "FROM search_temp"
, "GROUP BY "
, " word_text"
, ";"
)
, Sql__create_link__one = String_.Concat_lines_nl
( "INSERT INTO <link_db>search_link (word_id, page_id)"
, "SELECT w.word_id"
, ", t.page_id"
, "FROM search_temp t"
, " JOIN search_word w ON t.word_text = w.word_text"
, ";"
)
, Sql__create_link__many = String_.Concat_lines_nl
( "INSERT INTO <link_db>search_link (word_id, page_id)"
, "SELECT w.word_id"
, ", t.page_id"
, "FROM search_temp t"
, " JOIN search_word w ON t.word_text = w.word_text"
, " JOIN <page_db>page p ON t.page_id = p.page_id"
, "WHERE p.page_namespace {0}"
, ";"
)
;
}

View File

@@ -0,0 +1,182 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs.bldrs.cmds; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.dbs.*; import gplx.xowa.addons.searchs.dbs.bldrs.*;
import gplx.dbs.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.wkrs.*; import gplx.xowa.addons.sqlite_utils.bldrs.*;
import gplx.xowa.addons.searchs.dbs.*;
public class Srch__link__link_score extends Xob_cmd__base implements Xob_cmd {
private int score_multiplier = 100000000;
private boolean page_rank_enabled = false;
private boolean delete_plink_db = false;
public Srch__link__link_score(Xob_bldr bldr, Xowe_wiki wiki) {super(bldr, wiki);}
public Srch__link__link_score Page_rank_enabled_(boolean v) {this.page_rank_enabled = v; return this;}
public Srch__link__link_score Delete_plink_db_(boolean v) {this.delete_plink_db = v; return this;}
@Override public String Cmd_key() {return Xob_cmd_keys.Key_search__link__link_score;}
@Override public void Cmd_run() {
wiki.Init_assert();
Db_conn plink_conn = Db_conn_bldr.Instance.Get_or_autocreate(false, wiki.Fsys_mgr().Root_dir().GenSubFil(Xob_db_file.Name__page_link));
String page_rank_tbl = Srch__page__page_score.Pagerank__tbl_name;
String log_module = "search.page.score";
Xoa_app_.Plog_none(log_module, "adding fields to page_rank_temp");
plink_conn.Meta_fld_assert(page_rank_tbl, "page_len" , Dbmeta_fld_tid.Itm__int, 0);
plink_conn.Meta_fld_assert(page_rank_tbl, "page_len_score" , Dbmeta_fld_tid.Itm__int, 0);
plink_conn.Meta_fld_assert(page_rank_tbl, "page_rank_score" , Dbmeta_fld_tid.Itm__double, 0);
plink_conn.Meta_fld_assert(page_rank_tbl, "page_score" , Dbmeta_fld_tid.Itm__int, 0);
int link_score_max = Srch_search_addon.Score_max;
// percentize page_len_score to 0 : 100,000,000; NOTE: 100,000,000 so that no individual score should have 2+ page; i.e.: score_range > page_count
new Db_attach_mgr(plink_conn, new Db_attach_itm("page_db", wiki.Data__core_mgr().Tbl__page().conn))
.Exec_sql_w_msg("filling page_rank_temp.page_len", String_.Concat_lines_nl_skip_last
( "UPDATE page_rank_temp"
, "SET page_len = (SELECT page_len FROM <page_db>page p WHERE p.page_id = page_rank_temp.page_id)"
));
new Sqlite_percentile_cmd(bldr, wiki).Init_by_rel_url(Xob_db_file.Name__page_link, "temp_page_len", link_score_max, String_.Concat_lines_nl_skip_last
( "SELECT p.page_id, p.page_len"
, "FROM <page_db>page p"
, "ORDER BY p.page_len" // NOTE: ORDER BY is needed b/c INSERT into AUTO INCREMENT table
)).Cmd_run();
plink_conn.Exec_sql("finalizing page_rank_temp.page_len_score", String_.Concat_lines_nl_skip_last
( "UPDATE page_rank_temp"
, "SET page_len_score = (SELECT tpl.row_score FROM temp_page_len tpl WHERE tpl.row_key = page_rank_temp.page_id)"
));
// calc page_score
if (page_rank_enabled) {
// get min / max
Xoa_app_.Plog_none(log_module, "calculating page_rank range");
double page_rank_min = plink_conn.Exec_select_as_double("SELECT Min(page_rank) FROM " + page_rank_tbl, Double_.MinValue); if (page_rank_min == Double_.MinValue) throw Err_.new_("bldr", "failed to get min; tbl=~{0}", page_rank_tbl);
double page_rank_max = plink_conn.Exec_select_as_double("SELECT Max(page_rank) FROM " + page_rank_tbl, Double_.MinValue); if (page_rank_max == Double_.MinValue) throw Err_.new_("bldr", "failed to get max; tbl=~{0}", page_rank_tbl);
double page_rank_rng = page_rank_max - page_rank_min;
if (page_rank_rng == 0) page_rank_rng = 1; // if 0, set to 1 to prevent divide by 0 below;
String score_multiplier_as_str = Dbmeta_fld_itm.To_double_str_by_int(score_multiplier);
// normalize page_rank to 0 : 100,000,000
plink_conn.Exec_sql
( "normalizing page_rank_temp.page_rank_score"
, Bry_fmt.Make_str
("UPDATE ~{tbl} SET page_rank_score = ((Coalesce(page_rank, 0)) / ~{page_score_rng}) * ~{score_multiplier}"
, page_rank_tbl, Double_.To_str(page_rank_rng), score_multiplier_as_str)
);
// adjust for page_len where pages in lower 60% will get penalized; EX: page_rank = 100; page_len = 50,000,000 -> 100 * (50 M / 100 M) -> 50
String page_len_cutoff = Dbmeta_fld_itm.To_double_str_by_int((int)(score_multiplier * .6));
plink_conn.Exec_sql
( "penalizing short pages"
, Bry_fmt.Make_str(String_.Concat_lines_nl_skip_last
( "UPDATE page_rank_temp"
, "SET page_rank_score = (page_rank_score * CASE WHEN page_len_score < ~{page_len_cutoff} THEN (page_len_score / ~{score_multiplier}) ELSE 1 END)"
), page_len_cutoff, score_multiplier_as_str));
// percentize page_rank_score to 0 : 100,000
new Sqlite_percentile_cmd(bldr, wiki).Init_by_rel_url(Xob_db_file.Name__page_link, "temp_page_score", link_score_max, String_.Concat_lines_nl_skip_last
( "SELECT prt.page_id, prt.page_rank_score"
, "FROM page_rank_temp prt"
, "ORDER BY prt.page_rank_score" // NOTE: ORDER BY is needed b/c INSERT into AUTO INCREMENT table
)).Cmd_run();
plink_conn.Exec_sql
( "finalizing page_rank_temp.page_score"
, String_.Concat_lines_nl_skip_last
( "UPDATE page_rank_temp"
, "SET page_score = Cast((SELECT tmp.row_score FROM temp_page_score tmp WHERE tmp.row_key = page_rank_temp.page_id) AS int)"
));
}
else {
plink_conn.Exec_sql
( "finalizing page_rank_temp.page_score"
, String_.Format(String_.Concat_lines_nl_skip_last
( "UPDATE page_rank_temp"
, "SET page_score = Cast(page_len_score AS int)"
)));
}
plink_conn.Meta_idx_create(Xoa_app_.Usr_dlg(), Dbmeta_idx_itm.new_normal_by_tbl("page_rank_temp", "page_score", "page_id", "page_score"));
// update page table
Xowd_page_tbl page_tbl = wiki.Data__core_mgr().Tbl__page();
Db_conn page_conn = page_tbl.conn;
if (page_tbl.Fld_page_score() == Dbmeta_fld_itm.Key_null) {
page_conn.Meta_fld_append(page_tbl.Tbl_name(), Dbmeta_fld_itm.new_int(Xowd_page_tbl.Fld__page_score__key).Default_(0));
page_tbl = wiki.Data__core_mgr().Db__core().Tbl__page__rebind();
}
new Db_attach_mgr(page_conn, new Db_attach_itm("plink_db", plink_conn))
.Exec_sql_w_msg("updating page.page_score", String_.Concat_lines_nl_skip_last
( "UPDATE page"
, "SET page_score = Coalesce((SELECT Cast(pr.page_score AS integer) FROM <plink_db>page_rank_temp pr WHERE pr.page_id = page.page_id), 0)"
));
// update link tables
Srch_db_mgr search_db_mgr = Srch_search_addon.Get(wiki).Db_mgr();
Srch_word_tbl word_tbl = search_db_mgr.Tbl__word();
if (!page_tbl.conn.Eq(word_tbl.conn)) page_tbl.conn.Env_vacuum(); // don't vacuum if single-db
int link_tbls_len = search_db_mgr.Tbl__link__len();
for (int i = 0; i < link_tbls_len; ++i) {
Srch_link_tbl link_tbl = search_db_mgr.Tbl__link__get_at(i);
// update search_link.link_score
link_tbl.conn.Meta_fld_assert(link_tbl.tbl_name, Srch_link_tbl.Fld_link_score, Dbmeta_fld_tid.Itm__int, 0);
new Db_attach_mgr(link_tbl.conn
, new Db_attach_itm("page_db", page_conn)
).Exec_sql_w_msg
( Bry_fmt.Make_str("updating search_link.link_score: ~{idx} of ~{total}", i + 1, link_tbls_len)
, String_.Concat_lines_nl_skip_last
( "UPDATE search_link"
, "SET link_score = Coalesce((SELECT page_score FROM <page_db>page p WHERE p.page_id = search_link.page_id), 0)"
));
// update word_tbl.page_score_max
new Db_attach_mgr(word_tbl.conn
, new Db_attach_itm("link_db", link_tbl.conn)
)
.Exec_sql_w_msg
( Bry_fmt.Make_str("updating link_score_min: ~{idx} of ~{total}", i + 1, link_tbls_len)
, String_.Concat_lines_nl_skip_last
( "REPLACE INTO search_word (word_id, word_text, link_count, link_score_min, link_score_max)"
, "SELECT sw.word_id, sw.word_text, sw.link_count, Min(sl.link_score), sw.link_score_max"
, "FROM search_word sw"
, " JOIN <link_db>search_link sl ON sl.word_id = sw.word_id"
, "GROUP BY sw.word_id, sw.word_text, sw.link_count, sw.link_score_max"
, "HAVING sw.link_score_min > Min(sl.link_score)"
))
.Exec_sql_w_msg
( Bry_fmt.Make_str("updating link_score_max: ~{idx} of ~{total}", i + 1, link_tbls_len)
, String_.Concat_lines_nl_skip_last
( "REPLACE INTO search_word (word_id, word_text, link_count, link_score_min, link_score_max)"
, "SELECT sw.word_id, sw.word_text, sw.link_count, sw.link_score_min, Max(sl.link_score)"
, "FROM search_word sw"
, " JOIN <link_db>search_link sl ON sl.word_id = sw.word_id"
, "GROUP BY sw.word_id, sw.word_text, sw.link_count, sw.link_score_min"
, "HAVING sw.link_score_max < Max(sl.link_score)"
))
;
link_tbl.Create_idx__link_score();
if (!link_tbl.conn.Eq(word_tbl.conn)) link_tbl.conn.Env_vacuum(); // don't vacuum if single-db
word_tbl.Create_idx();
}
Srch_db_cfg_.Update__bldr__link(search_db_mgr.Tbl__cfg(), search_db_mgr.Cfg(), link_score_max);
if (delete_plink_db) {
Xob_db_file plink_db = Xob_db_file.New__page_link(wiki);
plink_db.Conn().Rls_conn();
Io_mgr.Instance.DeleteFil(plink_db.Url());
}
}
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__page_rank_enabled_)) page_rank_enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk__delete_plink_db_)) delete_plink_db = m.ReadYn("v");
else return GfoInvkAble_.Rv_unhandled;
return this;
} private static final String Invk__page_rank_enabled_ = "page_rank_enabled_", Invk__delete_plink_db_ = "delete_plink_db_";
}

View File

@@ -0,0 +1,109 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs.bldrs.cmds; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.dbs.*; import gplx.xowa.addons.searchs.dbs.bldrs.*;
import gplx.dbs.*; import gplx.dbs.qrys.*;
import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.addons.pagelinks.dbs.*;
import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.wkrs.*;
public class Srch__page__page_score extends Xob_cmd__base implements Xob_cmd { // create page_rank in page_db; drop and vaccuum later; avoid cross db for now
private double damping_factor = .85;
private double error_margin = .0001d;
private int iteration_max = 1000;
private Db_conn page_conn, plink_conn;
private int page_count = 0;
public Srch__page__page_score(Xob_bldr bldr, Xowe_wiki wiki) {super(bldr, wiki);}
public Srch__page__page_score Iteration_max_(int iteration_max) {this.iteration_max = iteration_max; return this;}
@Override public String Cmd_key() {return Xob_cmd_keys.Key_search__page__page_score;}
@Override public void Cmd_run() {
Init__tbl();
Calc__main();
}
private void Init__tbl() {
wiki.Init_assert();
this.page_conn = wiki.Data__core_mgr().Db__core().Conn();
page_count = page_conn.Exec_select_as_int("SELECT Count(page_id) FROM page", -1);
Xob_db_file page_link_db = Xob_db_file.New__page_link(wiki);
this.plink_conn = page_link_db.Conn();
if (plink_conn.Meta_tbl_exists(Pagerank__tbl_name)) plink_conn.Meta_tbl_drop(Pagerank__tbl_name);
Pglnk_page_link_tbl plink_tbl = new Pglnk_page_link_tbl(plink_conn);
if (!plink_conn.Meta_tbl_exists(plink_tbl.Tbl_name())) plink_tbl.Create_tbl();// create page_link if it doesn't exist; occurs when page_rank_enabled == false;
plink_conn.Meta_tbl_create(Dbmeta_tbl_itm.New
( Pagerank__tbl_name
, Dbmeta_fld_itm.new_int (Pagerank__fld_page_id).Primary_y_()
, Dbmeta_fld_itm.new_int (Pagerank__fld_link_count)
, Dbmeta_fld_itm.new_int (Pagerank__fld_has_converged).Default_(0)
, Dbmeta_fld_itm.new_double (Pagerank__fld_page_rank).Default_(1)
));
new Db_attach_mgr(plink_conn, new Db_attach_itm("page_db", page_conn))
.Exec_sql_w_msg("generating list of pages", String_.Concat_lines_nl_skip_last
( "INSERT INTO page_rank_temp (page_id, link_count)"
, "SELECT page_id"
, ", Coalesce(Count(pl.trg_id), {0}) AS link_count"
, "FROM <page_db>page p" // NOTE: JOIN needed to filter out [[User:]] pages which are in pagelinks.sql, but not in pages-articles.xml
, " LEFT JOIN page_link pl ON p.page_id = pl.src_id"
// , "WHERE p.page_namespace = 0"
, "GROUP BY p.page_id"
), page_count);
}
private void Calc__main() {
int iteration_idx = 0;
double damping_factor_inverse = 1 - damping_factor;
while (true) {
if (iteration_idx == iteration_max) break;
int converged_count = plink_conn.Exec_select_as_int("SELECT Count(page_id) FROM page_rank_temp WHERE has_converged = 0;", 0);
if (converged_count == 0) break;
new Db_attach_mgr(plink_conn, new Db_attach_itm("page_db", page_conn))
.Exec_sql_w_msg(String_.Format("calculating page_rank; iteration={0} unconverged={1}", iteration_idx, converged_count)
, String_.Concat_lines_nl_skip_last
( "REPLACE INTO page_rank_temp (page_id, page_rank, link_count, has_converged)"
, "SELECT pr.page_id"
, ", {1} + ({0} * Coalesce(w.page_rank, 0)) AS page_rank"
, ", pr.link_count"
, ", CASE WHEN Abs(pr.page_rank - ({1} + ({0} * Coalesce(w.page_rank, 0)))) < {2} THEN 1 ELSE 0 END AS has_converged"
, "FROM page_rank_temp pr"
, " LEFT JOIN"
, " (SELECT lnk.trg_id"
, " , Sum((Cast(pr2.page_rank AS double) / Cast(pr2.page_rank AS double))) * {0} AS page_rank"
, " FROM page_rank_temp pr2"
, " JOIN page_link lnk ON pr2.page_id = lnk.src_id"
, " JOIN <page_db>page p ON lnk.src_id = p.page_id"
// , " WHERE p.page_namespace = 0"
, " GROUP BY lnk.trg_id"
, " ) AS w ON w.trg_id = pr.page_id"
, "WHERE pr.has_converged = 0"
), damping_factor, damping_factor_inverse, error_margin);
++iteration_idx;
}
Gfo_usr_dlg_.Instance.Note_many("", "", "page_rank done; iteration=~{0}", iteration_idx);
}
public static final String
Pagerank__tbl_name = "page_rank_temp"
, Pagerank__fld_page_id = "page_id"
, Pagerank__fld_page_rank = "page_rank"
, Pagerank__fld_link_count = "link_count"
, Pagerank__fld_has_converged = "has_converged"
;
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__damping_factor_)) damping_factor = m.ReadDouble("v");
else if (ctx.Match(k, Invk__error_margin_)) error_margin = m.ReadDouble("v");
else if (ctx.Match(k, Invk__iteration_max_)) iteration_max = m.ReadInt("v");
else return GfoInvkAble_.Rv_unhandled;
return this;
} private static final String Invk__damping_factor_ = "damping_factor_", Invk__error_margin_ = "error_margin_", Invk__iteration_max_ = "iteration_max_";
}

View File

@@ -0,0 +1,52 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.dbs.bldrs.cmds; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.dbs.*; import gplx.xowa.addons.searchs.dbs.bldrs.*;
import gplx.dbs.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.wkrs.*; import gplx.xowa.addons.sqlite_utils.bldrs.*;
import gplx.xowa.addons.searchs.dbs.*;
public class Srch__word__link_count extends Xob_cmd__base implements Xob_cmd {
private int score_multiplier = Srch_search_addon.Score_max;
public Srch__word__link_count(Xob_bldr bldr, Xowe_wiki wiki) {super(bldr, wiki);}
@Override public String Cmd_key() {return Xob_cmd_keys.Key_search__word__link_count;}
@Override public void Cmd_run() {
wiki.Init_assert();
Srch_db_mgr search_db_mgr = Srch_search_addon.Get(wiki).Db_mgr();
Srch_word_tbl word_tbl = search_db_mgr.Tbl__word();
Db_conn word_conn = word_tbl.conn;
String percentile_tbl = "search_word__link_count";
Sqlite_percentile_cmd percentile_cmd = new Sqlite_percentile_cmd(bldr, wiki).Init_by_conn(word_conn, percentile_tbl, score_multiplier, String_.Concat_lines_nl_skip_last
( "SELECT sw.word_id, sw.link_count"
, "FROM search_word sw"
, "ORDER BY sw.link_count" // NOTE: ORDER BY is needed b/c INSERT into AUTO INCREMENT table
));
percentile_cmd.Cmd_run();
word_conn.Exec_sql("finalizing search_word.link_count_score", String_.Concat_lines_nl_skip_last
( "UPDATE search_word"
, "SET link_count_score = (SELECT tpl.row_score FROM search_word__link_count tpl WHERE tpl.row_key = search_word.word_id)"
));
word_conn.Meta_tbl_drop(percentile_tbl);
word_conn.Meta_idx_create(Dbmeta_idx_itm.new_normal_by_tbl(word_tbl.tbl_name, "link_count_score__word_text", word_tbl.fld_link_count_score, word_tbl.fld_text));
int link_count_score_cutoff = word_conn.Exec_select_as_int("SELECT Cast(Min(link_count_score) AS int) AS val FROM search_word WHERE link_count > " + Int_.To_str(Srch_db_cfg_.Link_count_score_cutoff), 0);
Srch_db_cfg_.Update__bldr__word(search_db_mgr.Tbl__cfg(), search_db_mgr.Cfg(), percentile_cmd.count, score_multiplier, link_count_score_cutoff);
word_conn.Env_vacuum();
}
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;}
}

View File

@@ -0,0 +1,117 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.core.btries.*;
import gplx.xowa.langs.cases.*;
public class Srch_highlight_mgr {
private final Xol_case_mgr case_mgr;
private final Bry_bfr tmp_bfr = Bry_bfr.new_(32);
private Srch_highlight_itm[] srch_lc_itms;
private int srch_words_len;
public Srch_highlight_mgr(Xol_case_mgr case_mgr) {this.case_mgr = case_mgr;}
public Srch_highlight_mgr Search_(byte[] srch_mc_bry) {
synchronized (tmp_bfr) {
// build array of search_words
byte[] srch_lc_bry = case_mgr.Case_build_lower(srch_mc_bry);
byte[][] srch_lc_ary = Bry_split_.Split(srch_lc_bry, Byte_ascii.Space, Bool_.Y);
this.srch_words_len = srch_lc_ary.length;
this.srch_lc_itms = new Srch_highlight_itm[srch_words_len];
for (int i = 0; i < srch_words_len; ++i) {
byte[] srch_lc_itm = srch_lc_ary[i];
srch_lc_itms[i] = new Srch_highlight_itm(i, srch_lc_itm);
}
// sort to search first by longest search_word; needed for searches like "A Abc" and titles like "Abc A", else "A" will match "Abc" and "Abc" will match nothing
Array_.Sort(srch_lc_itms, Srch_highlight_bry_sorter.Instance);
return this;
}
}
public byte[] Highlight(byte[] page_mc_bry) {
synchronized (tmp_bfr) {
byte[][] page_mc_words = Bry_split_.Split(page_mc_bry, Byte_ascii.Space, Bool_.Y);
byte[][] page_lc_words = Bry_split_.Split(case_mgr.Case_build_lower(page_mc_bry), Byte_ascii.Space, Bool_.Y);
int page_words_len = page_lc_words.length;
boolean[] page_words_done = new boolean[page_words_len];
// loop over search_words; EX: search_raw="a b" -> "a", "b"
for (int i = 0; i < srch_words_len; ++i) {
Srch_highlight_itm srch_lc_itm = srch_lc_itms[i];
byte[] srch_lc_word = srch_lc_itm.Word;
// loop over page_title words; EX: page_raw="A B C" -> "a", "b", "c"
for (int j = 0; j < page_words_len; ++j) {
byte[] page_lc_word = page_lc_words[j];
int find_pos = Bry_find_.Find_fwd(page_lc_word, srch_lc_word);
// skip: search is not in page; EX: page_raw="D e"; should not happen, but exit now else Array out of bounds exception below
if (find_pos == Bry_find_.Not_found) continue;
// skip: find_pos is not BOS and prv byte is not dash or paren; EX: "Za" should be skipped; "-a" and "(a" should not
if (find_pos > 0) {
byte prv_byte = page_lc_word[find_pos - 1];
if ( prv_byte != Byte_ascii.Dash
&& prv_byte != Byte_ascii.Paren_bgn
)
continue;
}
// skip: item already matched; EX: "a"; "a a"
if (page_words_done[j]) continue;
page_words_done[j] = true;
// NOTE: lc_idx is guaranteed to equal mc_idx
byte[] page_mc_word = page_mc_words[j];
int srch_lc_word_len = srch_lc_word.length;
// build new word; EX: "<strong>A</strong>"
tmp_bfr.Clear();
tmp_bfr.Add_mid(page_mc_word, 0, find_pos);
tmp_bfr.Add(gplx.langs.htmls.Gfh_tag_.Strong_lhs);
tmp_bfr.Add_mid(page_mc_word, find_pos, find_pos + srch_lc_word_len);
tmp_bfr.Add(gplx.langs.htmls.Gfh_tag_.Strong_rhs);
tmp_bfr.Add_mid(page_mc_word, find_pos + srch_lc_word_len, page_mc_word.length);
byte[] repl = tmp_bfr.To_bry_and_clear();
// overwrite page_title word
page_mc_words[j] = repl;
}
}
// rebuild page_words ary
for (int i = 0; i < page_words_len; ++i) {
if (i != 0) tmp_bfr.Add_byte_space(); // NOTE: this assumes one space separating titles which is true for all MW titles
tmp_bfr.Add(page_mc_words[i]);
}
return tmp_bfr.To_bry_and_clear();
}
}
}
class Srch_highlight_itm {
public Srch_highlight_itm(int idx, byte[] word) {this.Idx = idx; this.Word = word; this.Word_len = word.length;}
public final int Idx;
public final byte[] Word;
public final int Word_len;
}
class Srch_highlight_bry_sorter implements gplx.core.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Srch_highlight_itm lhs = (Srch_highlight_itm)lhsObj;
Srch_highlight_itm rhs = (Srch_highlight_itm)rhsObj;
return -Int_.Compare(lhs.Word_len, rhs.Word_len); // - for descending
}
public static final Srch_highlight_bry_sorter Instance = new Srch_highlight_bry_sorter(); Srch_highlight_bry_sorter() {}
}

View File

@@ -0,0 +1,47 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import org.junit.*; import gplx.xowa.langs.cases.*;
public class Srch_highlight_mgr_tst {
private final Srch_highlight_mgr_tstr tstr = new Srch_highlight_mgr_tstr();
@Test public void Full__one() {tstr.Test("a" , "A" , "<strong>A</strong>");}
@Test public void Full__many() {tstr.Test("a b" , "A B" , "<strong>A</strong> <strong>B</strong>");}
@Test public void Part__one() {tstr.Test("a" , "A1" , "<strong>A</strong>1");}
@Test public void Part__many() {tstr.Test("a b" , "A1 B1" , "<strong>A</strong>1 <strong>B</strong>1");}
@Test public void Unordered() {tstr.Test("b a" , "A1 B1" , "<strong>A</strong>1 <strong>B</strong>1");}
@Test public void Repeat__part() {tstr.Test("a ab" , "Ab A" , "<strong>Ab</strong> <strong>A</strong>");}
@Test public void Repeat__full() {tstr.Test("a" , "A A" , "<strong>A</strong> <strong>A</strong>");}
@Test public void Close() {tstr.Test("a" , "Ba Aa" , "Ba <strong>A</strong>a");}
@Test public void Comma() {tstr.Test("a" , "A, b" , "<strong>A</strong>, b");}
@Test public void Dash() {tstr.Test("b" , "A-B c" , "A-<strong>B</strong> c");}
@Test public void Parens() {tstr.Test("a" , "(A)" , "(<strong>A</strong>)");}
@Test public void Strong() {tstr.Test("strong" , "strong strong" , "<strong>strong</strong> <strong>strong</strong>");}
@Test public void Dash_w_mixed_cases() {tstr.Test("b" , "A-a B" , "A-a <strong>B</strong>");} // search_parser treats A-a separately from a-a
@Test public void Acronymn() {tstr.Test("ab" , "A.B." , "A.B.");}
// @Test public void Slash() {tstr.Test("b" , "A/B/C" , "A/<strong>B</strong>/C");}
}
class Srch_highlight_mgr_tstr {
private final Srch_highlight_mgr mgr;
private final Xol_case_mgr case_mgr = Xol_case_mgr_.A7();
public Srch_highlight_mgr_tstr() {
mgr = new Srch_highlight_mgr(case_mgr);
}
public void Test(String search, String title, String expd) {
Tfds.Eq(expd, String_.new_u8(mgr.Search_(Bry_.new_u8(search)).Highlight(Bry_.new_u8(title))));
}
}

View File

@@ -0,0 +1,262 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.core.btries.*; import gplx.core.primitives.*;
interface Srch_sym_parser {
int Tid();
byte[][] Hooks_ary();
int Parse(Srch_text_parser mgr, byte[] src, int src_end, int hook_bgn, int hook_end);
}
class Srch_sym_parser_ {
public static final int Tid__terminal = 1, Tid__split = 2, Tid__enclosure = 3, Tid__dot = 4, Tid__ellipsis = 5, Tid__apos = 6, Tid__dash = 7;
}
class Srch_sym_parser__terminal implements Srch_sym_parser {
public Srch_sym_parser__terminal(byte[] hook_bry) {this.hooks_ary = Bry_.Ary(hook_bry);}
public int Tid() {return Srch_sym_parser_.Tid__terminal;}
public byte[][] Hooks_ary() {return hooks_ary;} private final byte[][] hooks_ary;
public int Parse(Srch_text_parser mgr, byte[] src, int src_end, int hook_bgn, int hook_end) {
if (mgr.Cur__end__chk(hook_end)) { // hook at word_end; EX: "a, b" -> "a", "b"
int word_bgn = mgr.Cur__bgn();
if (word_bgn == Srch_text_parser.None) return hook_end;
int word_end = hook_bgn;
for (int i = hook_bgn - 1; i >= word_bgn; --i) { // loop bwd to gobble up streams of terminals; EX: "?!"
byte b = src[i];
if (mgr.word_end_trie.Match_bgn_w_byte(b, src, i, hook_bgn) == null) break;
word_end = i;
}
mgr.Words__add_if_pending_and_clear(word_end); // make word; note that " , " will not make word b/c word_bgn == -1
return hook_end;
}
else {}// hook at word_mid or word_bgn; noop; EX: "1,000" -> "1,000"; note that " ,abc" will ignore ","
// if (mgr.Cur__bgn() == - 1) {
// mgr.Cur__bgn__set(hook_bgn);
// }
// }
return hook_end;
}
}
class Srch_sym_parser__split implements Srch_sym_parser {
private final Btrie_slim_mgr trie = Btrie_slim_mgr.cs();
private final boolean handle_eos;
public Srch_sym_parser__split(boolean handle_eos, String... hooks_ary_as_str) {
this.handle_eos = handle_eos;
this.hooks_ary = Bry_.Ary(hooks_ary_as_str);
int hooks_len = hooks_ary.length;
for (int i = 0; i < hooks_len; ++i) {
byte[] hook = hooks_ary[i];
trie.Add_obj(hook, Int_obj_val.new_(hook.length));
}
}
public int Tid() {return Srch_sym_parser_.Tid__split;}
public byte[][] Hooks_ary() {return hooks_ary;} private final byte[][] hooks_ary;
public int Parse(Srch_text_parser mgr, byte[] src, int src_end, int hook_bgn, int hook_end) {
mgr.Words__add_if_pending_and_clear(hook_bgn);
int rv = hook_end;
while (rv < src_end) { // loop to skip multiple syms in same group; EX: "a \n\t\r b"
byte b = src[rv];
Object o = trie.Match_bgn_w_byte(b, src, rv, src_end);
if (o == null) break; // current sequence is not in grp; stop
Int_obj_val itm_len = (Int_obj_val)o;
rv += itm_len.Val(); // add len of sym to pos
}
return rv;
}
public int Find_fwd(byte[] src, int src_bgn, int src_end) {
for (int i = src_bgn; i < src_end; ++i) {
byte b = src[i];
Object o = trie.Match_bgn_w_byte(b, src, i, src_end);
if (o != null) return i;
}
return src_end;
}
public boolean Is_next(byte[] src, int pos, int end) {
if (pos >= end) return handle_eos;
byte b = src[pos];
Object o = trie.Match_bgn_w_byte(b, src, pos, end);
return o != null;
}
}
class Srch_sym_parser__paren_bgn implements Srch_sym_parser {
private final byte bgn_byte, end_byte;
public Srch_sym_parser__paren_bgn(byte bgn_byte, byte end_byte) {
this.bgn_byte = bgn_byte; this.end_byte = end_byte;
this.hooks_ary = Bry_.Ary(Bry_.New_by_byte(bgn_byte));
}
public int Tid() {return Srch_sym_parser_.Tid__enclosure;}
public byte[][] Hooks_ary() {return hooks_ary;} private final byte[][] hooks_ary;
public int Parse(Srch_text_parser mgr, byte[] src, int src_end, int paren_lhs_bgn, int paren_lhs_end) {
int word_bgn = mgr.Cur__bgn();
paren_lhs_end = Bry_find_.Find_fwd_while(src, paren_lhs_end, src_end, bgn_byte);
int paren_rhs_bgn = Bry_find_.Find_fwd(src, end_byte, paren_lhs_end, src_end);
if (paren_rhs_bgn == Bry_find_.Not_found) return paren_lhs_end; // paren_rhs missing; noop; NOTE: handles both "a(b" -> "a(b" and "a (b" -> "a", "b"
int paren_rhs_end = Bry_find_.Find_fwd_while(src, paren_rhs_bgn, src_end, end_byte);
int word_end = mgr.Cur__end__find__text_only(paren_lhs_end + 1);
if (word_end < paren_rhs_bgn)
word_end = mgr.Cur__end__find__text_only(paren_rhs_end);
boolean recurse = false;
if (word_bgn == -1) { // paren_lhs at word_bgn; EX: "a (b)"
if (word_end == paren_rhs_end) // paren_rhs at word_end; EX: "a (b) c"
recurse = true;
else { // paren_rhs at word_mid; EX: "a (b)c"
mgr.Words__add_direct(paren_lhs_bgn, word_end);
mgr.Words__add_direct(paren_rhs_end, word_end);
}
}
else { // paren_lhs at word_mid; EX: "a(b)"
mgr.Words__add_direct(word_bgn, word_end);
if (word_end == paren_rhs_end) // paren_rhs at word_end; EX: "a(b) c"
mgr.Words__add_direct(word_bgn, paren_lhs_bgn);
else {} // paren_rhs at word_mid; EX: "a (b)c"
mgr.Cur__bgn__reset();
}
if (recurse)
mgr.Make_copy().Parse(mgr.lcase, src, paren_lhs_end, paren_rhs_bgn);
return word_end;
}
}
class Srch_sym_parser__dot implements Srch_sym_parser { // handle periods which will add two entries; EX: "H. G. Wells" -> "H.", "G.", "H", "G", "Wells"
private final byte[] sym; private final int sym_len;
public Srch_sym_parser__dot(String sym_str) {this.sym = Bry_.new_u8(sym_str); this.sym_len = sym.length;}
public int Tid() {return Srch_sym_parser_.Tid__dot;}
public byte[][] Hooks_ary() {return Hooks_const;} private static final byte[][] Hooks_const = Bry_.Ary(".");
public int Parse(Srch_text_parser mgr, byte[] src, int src_end, int hook_bgn, int hook_end) {
int word_bgn = mgr.Cur__bgn();
if (word_bgn == -1) { // dot at start of word; EX: ".NET", "Colt .45"
int word_end = mgr.Cur__end__find(hook_bgn + 1);
if (word_end - hook_bgn == 1) return hook_end; // ignore stand-alone sym; EX: "a . . . b"
mgr.Words__add__chk_dash(hook_bgn, word_end); // make word; EX: ".45"
if (Bry_find_.Find_fwd(src, sym, hook_bgn + 1, word_end) == -1) // only add "root" word, if sym is not in middle of String; EX: ".int" -> "int"; ".A.B" x> "A.B"
mgr.Words__add__chk_dash(hook_bgn + 1, word_end); // make word; EX: "45"
mgr.Cur__bgn__reset();
return word_end;
}
else {
if (mgr.Cur__end__chk(hook_end)) { // at end of word; EX: "U.S.A. b" vs. "H. G. b"
mgr.Words__add__chk_dash(word_bgn, hook_end); // make word; EX: "vs."
if (Bry_find_.Find_fwd(src, sym, word_bgn, hook_bgn) == -1) // no dots in word; add "root" word; "vs." -> "vs.", "vs"; "U.S.A." -> "U.S.A." x> "U.S.A"
mgr.Words__add__chk_dash(word_bgn, hook_bgn); // make word; EX: "vs"
else {
for (int i = word_bgn; i < hook_end; ++i) { // dots in middle of String; extract word; EX: "U.S.A." -> USA
if (Bry_.Eq(src, i, i + sym_len, sym)) continue;// skip syms
mgr.Tmp_bfr.Add_byte(src[i]);
}
mgr.Words__add_direct(mgr.Tmp_bfr.To_bry_and_clear());
}
mgr.Cur__bgn__reset();
}
}
return hook_end;
}
}
class Srch_sym_parser__ellipsis implements Srch_sym_parser { // ellipsis which have variable length; EX: "..", "...", ".... "
private final byte ellipsis_byte;
public Srch_sym_parser__ellipsis(byte ellipsis_byte, String hook) {
this.ellipsis_byte = ellipsis_byte;
this.hooks_ary = Bry_.Ary(hook);
}
public int Tid() {return Srch_sym_parser_.Tid__ellipsis;}
public byte[][] Hooks_ary() {return hooks_ary;} private final byte[][] hooks_ary;
public int Parse(Srch_text_parser mgr, byte[] src, int src_end, int hook_bgn, int hook_end) {
mgr.Words__add_if_pending_and_clear(hook_bgn); // add word; EX: "Dreams" in "Dreams..."
int rv = Bry_find_.Find_fwd_while(src, hook_end, src_end, ellipsis_byte); // skip multiple ellipsis; EX: ......
mgr.Words__add__chk_dash(hook_bgn, rv); // add ellipsis
return rv;
}
}
class Srch_sym_parser__apos implements Srch_sym_parser { // apos which can be contraction ("I'm"), possessive ("today's") and plural ("plans'")
private final byte[] hook_bry;
public Srch_sym_parser__apos(String hook) {
this.hook_bry = Bry_.new_u8(hook);
this.hooks_ary = Bry_.Ary(hook_bry);
}
public int Tid() {return Srch_sym_parser_.Tid__apos;}
public byte[][] Hooks_ary() {return hooks_ary;} private final byte[][] hooks_ary;
public int Parse(Srch_text_parser mgr, byte[] src, int src_end, int hook_bgn, int hook_end) {
int word_bgn = mgr.Cur__bgn();
int word_end = -1;
if (word_bgn == -1) { // sym at word_bgn; EX: "'n'"
word_bgn = hook_bgn;
word_end = mgr.Cur__end__find(hook_bgn + 1);
mgr.Words__add__chk_dash(word_bgn, word_end);
// "'n'" -> "n"
int alt_word_bgn = word_bgn + 1;
int alt_word_end = Bry_find_.Find_bwd__skip(src, word_end, alt_word_bgn, hook_bry);
if (alt_word_end - alt_word_bgn > 0) // do not add if 0-len; EX: "' (disambiguation)"
mgr.Words__add__chk_dash(alt_word_bgn, alt_word_end);
mgr.Cur__bgn__reset();
return word_end;
}
word_end = mgr.Cur__end__find(hook_end);
if (hook_end == word_end) { // sym at word_end; EX: "A' "
mgr.Words__add_if_pending_and_clear(hook_bgn); // add root only; EX: "a'" -> "a" x> "a", "a'"
return hook_end;
}
else {
byte[] root_word = null;
if (hook_bgn - word_bgn == 1)
root_word = mgr.Tmp_bfr.Add_byte(src[word_bgn]).Add_mid(src, hook_bgn + 1, word_end).To_bry_and_clear();
else if (word_end - hook_end == 1)
root_word = mgr.Tmp_bfr.Add_mid(src, word_bgn, hook_bgn).Add_byte(src[hook_end]).To_bry_and_clear();
// Tfds.Write(word_bgn, hook_bgn, hook_end, word_end);
if (root_word != null) {
mgr.Words__add__chk_dash(word_bgn, word_end); // add full; EX: "o'clock"
mgr.Words__add_direct(root_word); // add root; EX: "oclock"
mgr.Cur__bgn__reset();
}
return word_end;
}
}
}
class Srch_sym_parser__dash implements Srch_sym_parser {
public Srch_sym_parser__dash(String hook) {this.hooks_ary = Bry_.Ary(hook);}
public int Tid() {return Srch_sym_parser_.Tid__dash;}
public byte[][] Hooks_ary() {return hooks_ary;} private final byte[][] hooks_ary;
public int Parse(Srch_text_parser mgr, byte[] src, int src_end, int hook_bgn, int hook_end) {
int cur_bgn = mgr.Cur__bgn(); // get word_bgn
if (cur_bgn == -1) { // no word_bgn; "-" is 1st char
if (mgr.Cur__end__chk(hook_end)) { // next char is space
mgr.Words__add_direct(hook_bgn, hook_end); // add dash; EX: "a - b" -> "a", "-", "b"
}
else { // next char is something else
mgr.Cur__bgn__set(hook_bgn); // update word_bgn to dash
mgr.Dash__bgn_(hook_end);
}
return hook_end;
}
else { // word_bgn exists
int dash_bgn = mgr.Dash__bgn();
if (dash_bgn == Srch_text_parser.None) { // 1st dash
mgr.Words__add__chk_dash(cur_bgn, hook_bgn);// add word; EX: "a" in "a-b"
} else { // 2nd or more; add stub; EX: "a-b-c"; 2nd "-" should add "b"
if (hook_bgn > dash_bgn) // only add if len > 0; handles multiple dashes; EX: "---"
mgr.Words__add_direct(dash_bgn, hook_bgn);
}
}
mgr.Dash__bgn_(hook_end);
return hook_end;
}
public void Add_pending_word(Srch_text_parser mgr, byte[] src, int word_end) {
int dash_bgn = mgr.Dash__bgn();
if (dash_bgn == Srch_text_parser.None) return;
if (word_end - dash_bgn > 0) // only add if there is word to right of dash; EX: "a-"
mgr.Words__add_direct(dash_bgn, word_end);
mgr.Dash__bgn_(Srch_text_parser.None); // clear the dash
}
}

View File

@@ -0,0 +1,173 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.core.btries.*; import gplx.xowa.langs.cases.*;
public class Srch_text_parser {
private Btrie_slim_mgr parser_trie = Btrie_slim_mgr.cs(); public Btrie_slim_mgr word_end_trie = Btrie_slim_mgr.cs(); private Btrie_slim_mgr word_bgn_trie = Btrie_slim_mgr.cs();
private Xol_case_mgr case_mgr;
public final Bry_bfr Tmp_bfr = Bry_bfr.new_(32);
private byte[] src; private int end;
private Srch_sym_parser__split parser__ws; private Srch_sym_parser__dash parser__dash;
public Srch_word_hash word_hash = new Srch_word_hash();
public boolean lcase = true;
public Srch_text_parser Init_for_ttl(Xol_case_mgr case_mgr) {
this.case_mgr = case_mgr;
parser_trie.Clear(); word_end_trie.Clear();
parser__ws = new Srch_sym_parser__split(Bool_.Y, " ", "\t", "\n", "\r", "_");
parser__dash = new Srch_sym_parser__dash("-");
Parsers__reg(Parsers__make__word_end
( "!", "?", ",", ":", ";", "\"", "~"
//, "@", "&", "*", "`", "+" // should add for symmetry of word_bgn trie but strips "@Home" to "Home" only; also, several have many "*", "`", "+"
));
Parsers__reg(new Srch_sym_parser__split(Bool_.N, "/"));
Parsers__reg(parser__ws, parser__dash
, new Srch_sym_parser__paren_bgn(Byte_ascii.Paren_bgn, Byte_ascii.Paren_end)
, new Srch_sym_parser__dot("."), new Srch_sym_parser__ellipsis(Byte_ascii.Dot, ".."), new Srch_sym_parser__apos("'")); // NOTE: [ ] { } do not exist in titles
word_bgn_trie.Add_many_int(1
// , "!", "?", ",", ":", ";" // low #; should add for symmetry of word_end trie;
, "\"" // adding for symmetry of word_end trie;
, "@", "&", "*", "`", "~", "+" // "@Home", "&c.", "&NSYNC", "Muhammad_ibn_`Ali_at-Tirmidhi"; "Phantom_~Requiem_for_the_Phantom~"; "+pool"
);
return this;
}
public Srch_text_parser Make_copy() {
Srch_text_parser rv = new Srch_text_parser();
rv.parser_trie = parser_trie; rv.word_end_trie = word_end_trie; rv.word_bgn_trie = word_bgn_trie;
rv.parser__ws = parser__ws; rv.parser__dash = parser__dash;
rv.word_hash = word_hash; rv.case_mgr = case_mgr;
rv.lcase = lcase;
return rv;
}
public byte[][] Parse_to_bry_ary(boolean lcase, byte[] src_orig) {
word_hash.Clear();
this.lcase = lcase;
Parse(lcase, src_orig, 0, src_orig.length);
int hash_len = word_hash.Len();
byte[][] rv = new byte[hash_len][];
for (int i = 0; i < hash_len; ++i) {
Srch_word_itm itm = (Srch_word_itm)word_hash.Get_at(i);
rv[i] = itm.Word;
}
return rv;
}
public void Parse(Srch_text_parser_wkr wkr, byte[] src_orig) {
word_hash.Clear();
Parse(Bool_.Y, src_orig, 0, src_orig.length);
int hash_len = word_hash.Len();
for (int i = 0; i < hash_len; ++i) {
Srch_word_itm itm = (Srch_word_itm)word_hash.Get_at(i);
wkr.Parse_done(itm);
}
}
public void Parse(boolean lcase, byte[] src_orig, int bgn, int end_orig) {
this.src = lcase ? case_mgr.Case_build_lower(src_orig) : src_orig;
this.end = end_orig + (src.length - src_orig.length);
this.cur_bgn = dash_bgn = Srch_text_parser.None;
int pos = bgn;
while (true) {
boolean pos_is_last = pos == end;
if (pos_is_last) { // EOS and pending word; add it
if (cur_bgn != -1)
Words__add__chk_dash(cur_bgn, end);
break;
}
byte b = src[pos];
Object o = parser_trie.Match_bgn_w_byte(b, src, pos, end);
if (o == null) { // unknown sequence; word-char
if (cur_bgn == -1) cur_bgn = pos; // set 1st char for word
++pos;
}
else {
Srch_sym_parser parser = (Srch_sym_parser)o;
pos = parser.Parse(this, src, end, pos, parser_trie.Match_pos());
}
}
}
public int Cur__bgn() {return cur_bgn;} private int cur_bgn; public void Cur__bgn__reset() {this.cur_bgn = -1;}
public void Cur__bgn__set(int v) {this.cur_bgn = v;} // called from dash parser
public int Dash__bgn() {return dash_bgn;} private int dash_bgn; public void Dash__bgn_(int v) {this.dash_bgn = v;}
public int Cur__end__find(int pos) {return parser__ws.Find_fwd(src, pos, end);}
public boolean Cur__end__chk(int pos) {return parser__ws.Is_next(src, pos, end);}
public int Cur__end__find__text_only(int pos) { // primarily for parens and finding word_end after ")"; EX: "(city), " vs "(a)b "
while (pos < end) {
byte b = src[pos];
Object parser_obj = parser_trie.Match_bgn_w_byte(b, src, pos, end);
if (parser_obj == null) // b is text; increment by 1 and continue searching
++pos;
else // b is some sort of symbol; end word here; EX: "a," should produce "a", not "a,"
return pos;
}
return end;
}
public void Words__add_if_pending_and_clear(int word_end) {
if (cur_bgn == -1) return; // exit; no pending words
this.Words__add__chk_dash(cur_bgn, word_end);
cur_bgn = -1;
}
public void Words__add__chk_dash(int word_bgn, int word_end) {
parser__dash.Add_pending_word(this, src, word_end);
byte[] word = Bry_.Mid(src, word_bgn, word_end);
Words__add_direct(word);
}
public void Words__add_direct(int bgn, int end) {Words__add_direct(Bry_.Mid(src, bgn, end));}
public void Words__add_direct(byte[] bry) {
word_hash.Add(bry);
// remove punctuation at bgn of word; EX: "@Home" -> "Home"
boolean dirty = false;
int pos = 0; int len = bry.length;
while (pos < len) {
byte b = bry[pos];
if (word_bgn_trie.Match_bgn_w_byte(b, bry, pos, len) != null) { // b is symbol;
dirty = true;
pos = word_bgn_trie.Match_pos();
}
else {
break;
}
}
if (dirty && pos < len) {
byte[] trunc = Bry_.Mid(bry, pos, len);
// if (!word_hash.Has(trunc)) // don't add if it exists; EX: "'tis"
word_hash.Add(trunc);
}
}
private void Parsers__reg(Srch_sym_parser... parsers_ary) {
int parsers_len = parsers_ary.length;
for (int i = 0; i < parsers_len; ++i) {
Srch_sym_parser parser = parsers_ary[i];
byte[][] hooks_ary = parser.Hooks_ary();
int hooks_len = hooks_ary.length;
for (int j = 0; j < hooks_len; ++j) {
byte[] hook = hooks_ary[j];
parser_trie.Add_obj(hook, parser);
if (parser.Tid() == Srch_sym_parser_.Tid__terminal)
word_end_trie.Add_obj(hook, parser);
}
}
}
private static Srch_sym_parser[] Parsers__make__word_end(String... hooks) {
int rv_len = hooks.length;
Srch_sym_parser[] rv = new Srch_sym_parser[rv_len];
for (int i = 0; i < rv_len; ++i)
rv[i] = new Srch_sym_parser__terminal(Bry_.new_u8(hooks[i]));
return rv;
}
public static final int None = -1;
}

View File

@@ -0,0 +1,147 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import org.junit.*; import gplx.xowa.langs.cases.*;
public class Srch_text_parser_tst {
private final Srch_text_parser_fxt fxt = new Srch_text_parser_fxt();
@Before public void init() {fxt.Init();}
@Test public void Word__one() {fxt.Clear().Test__split("abcd" , "abcd");}
@Test public void Word__many() {fxt.Clear().Test__split("abc d ef" , "abc", "d", "ef");}
@Test public void Ws__many() {fxt.Clear().Test__split("a b" , "a", "b");}
@Test public void Ws__bgn() {fxt.Clear().Test__split(" a" , "a");}
@Test public void Ws__end() {fxt.Clear().Test__split("a " , "a");}
@Test public void Under() {fxt.Clear().Test__split("a_b" , "a", "b");} // NOTE: same as space
@Test public void Lowercase() {fxt.Clear().Test__split("A B C" , "a", "b", "c");}
@Test public void Dupe() {fxt.Clear().Test__split("a a a" , fxt.Make_word("a", 3));}
@Test public void Dupe__lowercase() {fxt.Clear().Test__split("a A" , fxt.Make_word("a", 2));}
@Test public void Comma__end() {fxt.Clear().Test__split("a, b" , "a", "b");} // EX: "Henry VI, Part 3"; "Bergen County, New Jersey"
@Test public void Comma__mid() {fxt.Clear().Test__split("a,b" , "a,b");} // EX: "20,000 Leagues Under the Sea"
@Test public void Comma__bgn() {fxt.Clear().Test__split(",a b" , "a", "b");} // EX: skip bad usages; EX: "Little Harbour,Pictou ,Nova Scotia"; "The Hindu Succession Act ,1956"
@Test public void Colon__end() {fxt.Clear().Test__split("a: b" , "a", "b");}
@Test public void Colon__mid() {fxt.Clear().Test__split("a:b" , "a:b");} // EX: "3:10 to Yuma (2007 film)"; "6:02 AM EST"; "24:7 Theatre Festival"; "Library of Congress Classification:Class P -- Language and Literature"
@Test public void Colon__bgn() {fxt.Clear().Test__split(":a b" , "a", "b");}
@Test public void Semic__end() {fxt.Clear().Test__split("a; b" , "a", "b");}
@Test public void Semic__mid() {fxt.Clear().Test__split("a;b" , "a;b");}
@Test public void Semic__bgn() {fxt.Clear().Test__split(";a b" , "a", "b");}
@Test public void Bang__end() {fxt.Clear().Test__split("a! b" , "a", "b");}
@Test public void Bang__mid() {fxt.Clear().Test__split("a!b" , "a!b");}
@Test public void Bang__bgn() {fxt.Clear().Test__split("!a b" , "a", "b");}
@Test public void Question__end() {fxt.Clear().Test__split("a? b" , "a", "b");}
@Test public void Question__mid() {fxt.Clear().Test__split("a?b" , "a?b");}
@Test public void Question__bgn() {fxt.Clear().Test__split("?a b" , "a", "b");}
@Test public void Question__sentence() {fxt.Clear().Test__split("a?" , "a");}
@Test public void Multiple__1() {fxt.Clear().Test__split("a?!" , "a");}
@Test public void Multiple__2() {fxt.Clear().Test__split("a!?" , "a");}
@Test public void Dot__word() {fxt.Clear().Test__split("a.org" , "a.org");} // EX: "en.wikipedia.org"; "Earth.png"; "IEEE_802.15"
@Test public void Dot__abrv() {fxt.Clear().Test__split("a vs. b" , "a", "vs.", "vs", "b");} // EX: "vs.", "no.", "dr.", "st.", "inc."
@Test public void Dot__initials() {fxt.Clear().Test__split("a. b. cde" , "a.", "a", "b.", "b", "cde");} // EX: "H. G. Wells"
@Test public void Dot__acronym() {fxt.Clear().Test__split("abc D.E.F. ghi" , "abc", "d.e.f.", "def", "ghi");} // EX: "History of U.S.A. Science", "G.I. Bill", "Washington, D.C."; "Barcelona F.C."; "The Office (U.S.)"; "Agents of S.H.I.E.L.D."; "Gunfight at the O.K. Corral"; "H.M.S. Pinafore"; "R.E.M. discography"
@Test public void Dot__bgn() {fxt.Clear().Test__split("a .bcd e" , "a", ".bcd", "bcd", "e");} // EX: "Colt .45", "List of organizations with .int domain names"
@Test public void Dot__bgn__end() {fxt.Clear().Test__split("a .b. c" , "a", ".b.", "c");}
@Test public void Dot__ellipsis_like() {fxt.Clear().Test__split("a . . . b" , "a", "b");} // EX: "Did you know . . ."
@Test public void Ellipsis__len_3() {fxt.Clear().Test__split("a... bc d" , "a", "...", "bc", "d");} // EX: "Nights into Dreams..."
@Test public void Ellipsis__len_3__bgn() {fxt.Clear().Test__split("a ...b" , "a", "...", "b"); ;} // NOTE: make sure "dot_bgn" code doesn't break this
@Test public void Ellipsis__len_2() {fxt.Clear().Test__split("a.. b" , "a", "..", "b");} // EX: "3.. 6.. 9 Seconds of Light"
@Test public void Ellipsis__bgn() {fxt.Clear().Test__split("...a" , "...", "a");}
@Test public void Ellipsis__end() {fxt.Clear().Test__split("a..." , "a", "...");}
@Test public void Ellipsis__no_ws() {fxt.Clear().Test__split("a...b" , "a", "...", "b");}
@Test public void Ellipsis__term() {fxt.Clear().Test__split("a...?!" , "a", "...");} // EX: "Wetten, dass..?"
@Test public void Apos__merge__end__eos() {fxt.Clear().Test__split("ab's" , "ab's", "abs");} // EX: "A Midsummer Night's Dream"; "Director's cut"
@Test public void Apos__merge__end__word() {fxt.Clear().Test__split("ab's c" , "ab's", "abs", "c");} // EX: "Director's cut"; "Cap'n Crunch";
@Test public void Apos__merge__bgn() {fxt.Clear().Test__split("a o'bc" , "a", "o'bc", "obc");} // EX: "Twelve O'Clock High"; "Shaqille O'Neal"; "Banca d'Italia"
@Test public void Apos__merge__mid() {fxt.Clear().Test__split("i'm" , "i'm", "im");}
@Test public void Apos__bgn__long() {fxt.Clear().Test__split("a 'tis b" , "a", "'tis", "tis", "b");} // EX: "My Country, 'Tis of Thee"; "Omaha hold 'em"; "Slash'EM"; "Expo '92"
@Test public void Apos__end__eos() {fxt.Clear().Test__split("a'" , "a");}
@Test public void Apos__end__short() {fxt.Clear().Test__split("a' b" , "a", "b");} // EX: "Will-o'-the-wisp"; "Portuguese man o' war";
@Test public void Apos__end__long() {fxt.Clear().Test__split("ab' c" , "ab", "c");} // EX: "Dunkin' Donuts"; "'Allo 'Allo!"; "Catherine de' Medici"
@Test public void Apos__both__n() {fxt.Clear().Test__split("a 'n' b" , "a", "'n'", "n", "b");} // EX: "Rock 'n' Roll"; "Town 'n' Country, Florida"; "Hill 'n Dale, Florida"; "Chip 'n Dale Rescue Rangers"
@Test public void Apos__multiple() {fxt.Clear().Test__split("ab''cd" , "ab''cd");}
@Test public void Apos__lone() {fxt.Clear().Test__split("' a" , "'", "a");} // EX: "' (disambiguation)"
@Test public void Dash__one() {fxt.Clear().Test__split("a-b" , "a", "b", "a-b");} // EX: "The Amazing Spider-Man"; "On-super percentage"; "Basic Role-Playing"; "Context-sensitive"; "Cross-country skiing"; "Double-barreled shotgun"; "Dot-com bubble"; "Many-worlds interpretation"; "Faster-than-light"; "Gram-positive bacteria"; "Half-life", "Jean-Paul Sartre"; "Austria-Hungary"
@Test public void Dash__many() {fxt.Clear().Test__split("a-b-c" , "a", "b", "c", "a-b-c");}
@Test public void Dash__ws() {fxt.Clear().Test__split("a - b" , "a", "-", "b");}
@Test public void Dash__eos() {fxt.Clear().Test__split("a-" , "a", "a-");}
@Test public void Dash__bos() {fxt.Clear().Test__split("-a" , "a", "-a");}
@Test public void Dash__mult__2() {fxt.Clear().Test__split("--" , "--");}
@Test public void Dash__mult__3() {fxt.Clear().Test__split("---" , "---");}
@Test public void Dash__mult__2__words() {fxt.Clear().Test__split("a--b" , "a", "b", "a--b");}
@Test public void Dash__w_comma() {fxt.Clear().Test__split("a-, b" , "a", "a-", "b");}
@Test public void Slash__one() {fxt.Clear().Test__split("a/b" , "a", "b");} // EX: "Good cop/bad cop"; "Snooker world rankings 2004/2005"; "Debian GNU/Hurd"; "HIV/AIDS in the United States"; "List of minor planets/1<>100"
@Test public void Slash__many() {fxt.Clear().Test__split("a/b/c" , "a", "b", "c");} // EX: "Age/sex/location";
@Test public void Slash__ws() {fxt.Clear().Test__split("a / b" , "a", "b");}
@Test public void Dash__slash() {fxt.Clear().Test__split("a-b/c-d-e/f-g" , "a", "b", "a-b", "c", "d", "e", "c-d-e", "f", "g", "f-g");}
@Test public void Paren__both__one() {fxt.Clear().Test__split("a (b) c" , "a", "b", "c");} // EX: "A (letter)"
@Test public void Paren__both__many() {fxt.Clear().Test__split("a (b c) d" , "a", "b", "c", "d");} // EX: "A (2016 film)"
@Test public void Paren__bgn__multiple() {fxt.Clear().Test__split("a (((b)))" , "a", "b");}
@Test public void Paren__unmatched() {fxt.Clear().Test__split("a(b" , "a(b");}
@Test public void Paren__unmatched__bgn() {fxt.Clear().Test__split("a (b" , "a", "b");}
@Test public void Paren__mid() {fxt.Clear().Test__split("a(b)c" , "a(b)c");} // EX: "Chloro(pyridine)cobaloxime"; "Exi(s)t"
@Test public void Paren__end() {fxt.Clear().Test__split("a(b)" , "a(b)", "a");} // EX: "Come What(ever) May"; "501(c) organization"; "Reindeer(s) Are Better Than People"; "(Miss)understood"; "Chromium(III) picolinate"
@Test public void Paren__bgn() {fxt.Clear().Test__split("(a)b" , "(a)b", "b");} // EX: "International Student Congress of (bio)Medical Sciences"
@Test public void Paren__end__dash() {fxt.Clear().Test__split("a(b-c) d" , "a(b-c)", "a", "d");} // EX: "Bis(2-ethylhexyl) phthalate"
@Test public void Paren__end__comma() {fxt.Clear().Test__split("a(b,c) d" , "a(b,c)", "a", "d");} // EX: "Iron(II,III) oxide"
@Test public void Paren__comma() {fxt.Clear().Test__split("a (b), c" , "a", "b", "c");} // EX: "Corning (city), New York"
@Test public void Paren__multiple() {fxt.Clear().Test__split("(a) (b)" , "a", "b");}
@Test public void Quote__both() {fxt.Clear().Test__split("a \"b\" c" , "a", "b", "c");}
@Test public void Word_bgn__at() {fxt.Clear().Test__split("@a" , "@a", "a");}
@Test public void Word_bgn__tilde() {fxt.Clear().Test__split("~a~" , "a");} // EX: "Phantom ~Requiem for the Phantom~"
}
class Srch_text_parser_fxt {
private final Srch_text_parser word_parser = new Srch_text_parser();
private final Bry_bfr tmp_bfr = Bry_bfr.new_(32);
private Xol_case_mgr case_mgr;
public void Init() {
case_mgr = Xol_case_mgr_.A7();
word_parser.Init_for_ttl(case_mgr);
}
public Srch_text_parser_fxt Clear() {
word_parser.word_hash.Clear();
return this;
}
public Srch_word_itm Make_word(String raw, int count) {return new Srch_word_itm(Bry_.new_u8(raw)).Count_(count);}
public void Test__split(String src, String... expd_words) {
int len = expd_words.length;
Srch_word_itm[] ary = new Srch_word_itm[len];
for (int i = 0; i < len; ++i) {
ary[i] = Make_word(expd_words[i], 1);
}
Test__split(src, ary);
}
public void Test__split(String src, Srch_word_itm... expd_words) {
byte[] src_bry = Bry_.new_u8(src);
word_parser.Parse(Bool_.Y, src_bry, 0, src_bry.length);
Tfds.Eq_str_lines(To_str(expd_words), To_str(word_parser.word_hash));
}
private String To_str(Srch_word_itm[] word_ary) {
int len = word_ary.length;
for (int i = 0; i < len; ++i) {
if (i != 0) tmp_bfr.Add_byte_nl();
Srch_word_itm word = word_ary[i];
tmp_bfr.Add(word.Word).Add_byte_pipe();
tmp_bfr.Add_int_variable(word.Count());
}
return tmp_bfr.To_str_and_clear();
}
private String To_str(Srch_word_hash word_mgr) {
int len = word_mgr.Len();
Srch_word_itm[] ary = new Srch_word_itm[len];
for (int i = 0; i < len; ++i)
ary[i] = word_mgr.Get_at(i);
return To_str(ary);
}
}

View File

@@ -0,0 +1,25 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
public interface Srch_text_parser_wkr {
void Parse_done(Srch_word_itm word);
}
class Srch_text_parser_wkr__noop implements Srch_text_parser_wkr {
public void Parse_done(Srch_word_itm word) {}
public static final Srch_text_parser_wkr__noop Instance = new Srch_text_parser_wkr__noop(); Srch_text_parser_wkr__noop() {}
}

View File

@@ -0,0 +1,33 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
public class Srch_word_hash {
private final Ordered_hash hash = Ordered_hash_.New_bry();
public void Clear() {hash.Clear();}
public int Len() {return hash.Count();}
public boolean Has(byte[] word) {return hash.Has(word);}
public Srch_word_itm Get_at(int i) {return (Srch_word_itm)hash.Get_at(i);}
public void Add(byte[] word) {
Srch_word_itm itm = (Srch_word_itm)hash.Get_by(word);
if (itm == null) {
itm = new Srch_word_itm(word);
hash.Add(word, itm);
}
itm.Count_add_1_();
}
}

View File

@@ -15,10 +15,14 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
class Srch_rslt_list {
private final List_adp list = List_adp_.new_();
public int Len() {return list.Count();}
public void Add(Srch_rslt_itm rslt) {list.Add(rslt);}
public Srch_rslt_itm Get_at(int i) {return (Srch_rslt_itm)list.Get_at(i);}
package gplx.xowa.addons.searchs.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
public class Srch_word_itm {
public Srch_word_itm(byte[] word) {
this.Word = word;
this.count = 0;
}
public final byte[] Word;
public int Count() {return count;} private int count;
public void Count_add_1_() {++count;}
@gplx.Internal protected Srch_word_itm Count_(int v) {this.count = v; return this;}
}

View File

@@ -15,25 +15,27 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
package gplx.xowa.addons.searchs.searchers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.core.primitives.*;
import gplx.xowa.wikis.nss.*;
public class Xows_ns_mgr {
private final Ordered_hash ns_hash = Ordered_hash_.New(); private final Int_obj_ref tmp_ns_id = Int_obj_ref.neg1_(); private final Bry_bfr tmp_bfr = Bry_bfr.reset_(32);
public class Srch_ns_mgr {
private final Ordered_hash ns_hash = Ordered_hash_.New(); private final Int_obj_ref tmp_ns_id = Int_obj_ref.neg1_();
private final Bry_bfr tmp_bfr = Bry_bfr.reset_(32);
private boolean ns_all, ns_main;
public void Clear() {
ns_hash.Clear();
ns_all = ns_main = false;
}
public boolean Ns_main_only() {return ns_main;}
public boolean Has(int ns_id) {
return ns_all // all flag set
|| ns_main && ns_id == Xow_ns_.Tid__main // main flag set
|| ns_hash.Has(tmp_ns_id.Val_(ns_id)) // check against ns_hash
;
return ns_all // ns_all always returns true
|| ns_main && ns_id == Xow_ns_.Tid__main // ns_main returns true if main_ns
|| ns_hash.Has(tmp_ns_id.Val_(ns_id)); // ns_hash returns true if has ns_id
}
public void Add_by_id(int ns_id) {
if (ns_hash.Has(tmp_ns_id.Val_(ns_id)))
ns_hash.Del(tmp_ns_id);
public void Add_all() {ns_all = true;}
public Srch_ns_mgr Add_main_if_empty() {if (ns_hash.Count() == 0) ns_main = true; return this;}
public void Add_by_id(int ns_id) {
if (ns_hash.Has(tmp_ns_id.Val_(ns_id))) ns_hash.Del(tmp_ns_id);
ns_hash.Add_as_key_and_val(Int_obj_ref.new_(ns_id));
}
public void Add_by_name(byte[] ns_name) {
@@ -41,14 +43,11 @@ public class Xows_ns_mgr {
if (id != Xow_ns_.Tid__null)
Add_by_id(id);
}
public void Add_all() {
ns_all = true;
}
public void Add_by_parse(byte[] key, byte[] val) {
int ns_enabled = Bry_.To_int_or_neg1(val);
if (ns_enabled == 1) { // make sure set to 1; EX: ignore &ns0=0
int key_len = key.length;
if (key_len == 3 && key[2] == Byte_ascii.Star) // translate ns* as ns_all
if (key_len == 3 && key[2] == Srch_search_addon.Wildcard__star) // key=ns* sets ns_all to true
ns_all = true;
else {
int ns_id = Bry_.To_int_or(key, 2, key_len, Int_.Min_value);
@@ -59,15 +58,9 @@ public class Xows_ns_mgr {
}
}
}
public void Add_main_if_empty() {
if (ns_hash.Count() == 0)
ns_main = true;
}
public byte[] To_hash_key() {
if (ns_all)
return Hash_key_all;
else if (ns_main)
return Hash_key_main;
if (ns_all) return Hash_key_all;
else if (ns_main) return Hash_key_main;
else {
int ns_hash_len = ns_hash.Count();
for (int i = 0; i < ns_hash_len; i++) {
@@ -78,5 +71,29 @@ public class Xows_ns_mgr {
return tmp_bfr.To_bry_and_clear();
}
}
private static final byte[] Hash_key_all = new byte[] {Byte_ascii.Star}, Hash_key_main = new byte[] {Byte_ascii.Num_0};
public void Add_by_int_ids(int[] ns_ids) {
this.Clear();
if (ns_ids.length == 0) {
this.Add_all();
} else if (ns_ids.length == 1 && ns_ids[0] == Xow_ns_.Tid__main) {
this.Add_main_if_empty();
} else {
for (int ns_id : ns_ids)
this.Add_by_id(ns_id);
}
}
public int[] To_int_ary() {
if (ns_all) return Int_.Ary_empty;
else if (ns_main) return Int_.Ary(Xow_ns_.Tid__main);
else {
int len = ns_hash.Count();
int[] rv = new int[len];
for (int i = 0; i < len; i++) {
Int_obj_ref ns_id_ref = (Int_obj_ref)ns_hash.Get_at(i);
rv[i] = ns_id_ref.Val();
}
return rv;
}
}
private static final byte[] Hash_key_all = new byte[] {Srch_search_addon.Wildcard__star}, Hash_key_main = new byte[] {Byte_ascii.Num_0};
}

View File

@@ -0,0 +1,55 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.xowa.addons.searchs.searchers.rslts.*;
import gplx.xowa.addons.searchs.searchers.crts.*;
public class Srch_search_cmd implements Cancelable, GfoInvkAble {
private final Srch_search_mgr search_mgr;
public final Srch_search_qry qry;
public final Srch_crt_mgr crt_mgr;
private final Srch_rslt_cbk rslt_cbk;
private final Srch_rslt_list rslts_list;
public Srch_search_cmd(Srch_search_mgr search_mgr, Srch_search_qry qry, Srch_crt_mgr crt_mgr, Srch_rslt_cbk rslt_cbk, Srch_rslt_list rslts_list) {
this.search_mgr = search_mgr; this.qry = qry; this.crt_mgr = crt_mgr; this.rslt_cbk = rslt_cbk; this.rslts_list = rslts_list;
}
public boolean Canceled() {return canceled;} private boolean canceled;
public void Cancel() {
canceled = true;
rslt_cbk.On_cancel();
}
private void Search() {
try {
search_mgr.Search_async(this, qry, crt_mgr, rslt_cbk, rslts_list); // NOTE: must handle any errors in async mode
}
catch(Exception e) {
Xoa_app_.Usr_dlg().Prog_many("", "", "error during search: err=~{0}", Err_.Message_gplx_log(e));
}
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__search)) Search();
else return GfoInvkAble_.Rv_unhandled;
return this;
}
public static final String Invk__search = "search";
public static Srch_search_cmd Noop() {
if (noop == null) {
noop = new Srch_search_cmd(null, null, null, Srch_rslt_cbk_.Noop, null);
}
return noop;
} private static Srch_search_cmd noop;
}

View File

@@ -0,0 +1,69 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.xowa.langs.cases.*;
import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.addons.searchs.dbs.*;
import gplx.xowa.addons.searchs.searchers.crts.*; import gplx.xowa.addons.searchs.searchers.rslts.*; import gplx.dbs.percentiles.*; import gplx.xowa.addons.searchs.searchers.wkrs.*;
import gplx.xowa.addons.searchs.parsers.*;
public class Srch_search_ctx {
public Srch_search_ctx(Cancelable cxl, Xow_wiki wiki, Srch_search_addon addon
, Srch_rslt_list cache__page, Hash_adp_bry cache__word_counts
, Srch_search_qry qry, Srch_crt_scanner_syms scanner_syms, Srch_crt_mgr crt_mgr, Srch_rslt_list rslts_list) {
this.Cxl = cxl;
this.Wiki = wiki;
this.Wiki_domain = wiki.Domain_bry();
this.Case_mgr = wiki.Case_mgr();
this.Addon = addon;
this.Cache__page = cache__page;
this.Cache__word_counts = cache__word_counts;
this.Qry = qry;
this.Scanner_syms = scanner_syms;
this.Crt_mgr = crt_mgr;
this.Crt_mgr__root = crt_mgr.Root;
this.Rslts_list = rslts_list;
this.Db__core = wiki.Data__core_mgr().Db__core();
this.Tbl__page = Db__core.Tbl__page();
this.Tbl__word = addon.Db_mgr().Tbl__word();
this.Tbl__link__ary = addon.Db_mgr().Tbl__link__ary();
long page_count = wiki.Stats().Num_pages();
this.Score_rng.Init(page_count, addon.Db_mgr().Cfg().Link_score_max());
int rslts_needed = qry.Slab_end - rslts_list.Len();
if (rslts_needed < 0) rslts_needed = 0;
this.Rslts_needed = rslts_needed;
this.Highlight_mgr = new Srch_highlight_mgr(this.Case_mgr).Search_(qry.Phrase.Orig);
}
public final Cancelable Cxl;
public final Xow_wiki Wiki;
public final byte[] Wiki_domain;
public final Srch_search_addon Addon;
public final Xol_case_mgr Case_mgr;
public final Srch_rslt_list Cache__page;
public final Hash_adp_bry Cache__word_counts;
public final Xowd_db_file Db__core;
public final Xowd_page_tbl Tbl__page;
public final Srch_word_tbl Tbl__word;
public final Srch_link_tbl[] Tbl__link__ary;
public final Srch_search_qry Qry;
public final Srch_crt_scanner_syms Scanner_syms;
public final Srch_rslt_list Rslts_list;
public final int Rslts_needed;
public final Percentile_rng Score_rng = new Percentile_rng();
public final Srch_crt_mgr Crt_mgr;
public final Srch_crt_itm Crt_mgr__root;
public final Srch_highlight_mgr Highlight_mgr;
}

View File

@@ -0,0 +1,85 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.xowa.addons.searchs.searchers.rslts.*; import gplx.xowa.addons.searchs.searchers.wkrs.*; import gplx.xowa.addons.searchs.parsers.*; import gplx.xowa.addons.searchs.searchers.crts.*;
import gplx.xowa.addons.searchs.searchers.crts.visitors.*;
public class Srch_search_mgr {
private final Srch_search_addon addon;
private final Xow_wiki wiki;
private final Srch_rslt_list cache__page = new Srch_rslt_list();
private final Hash_adp_bry cache__word_counts = Hash_adp_bry.cs();
private final Srch_rslt_cache cache__rslts = new Srch_rslt_cache();
private final Srch_page_tbl_wkr page_tbl_searcher = new Srch_page_tbl_wkr();
private final Srch_crt_parser crt_parser;
private final Srch_search_cmd[] cur_cmds;
private final Object mutex = new Object();
private int search_count;
public Srch_search_mgr(Srch_search_addon addon, Xow_wiki wiki, Srch_text_parser parser) {
this.addon = addon; this.wiki = wiki;
crt_parser = new Srch_crt_parser(Scanner_syms);
// init cur_cmds with Noop cmd to make cancel logic below easier
int len = Srch_search_qry.Tid_len;
this.cur_cmds = new Srch_search_cmd[Srch_search_qry.Tid_len];
for (int i = 0; i < len; ++i)
cur_cmds[i] = Srch_search_cmd.Noop();
}
public void Clear_rslts_cache() {cache__rslts.Clear();}
public void Search_cancel() {
cur_cmds[Srch_search_qry.Tid__suggest_box].Cancel();
}
public void Search(Srch_search_qry qry, Srch_rslt_cbk cbk) {
if (qry.Phrase.Orig.length == 0) return;
// handle obsolete search dbs;
if (addon.Db_mgr().Cfg().Version_id__needs_upgrade()) {
addon.Db_mgr().Upgrade_mgr.Upgrade();
return;
}
// cancel existing cmd
Srch_search_cmd cur_cmd = cur_cmds[qry.Tid];
cur_cmd.Cancel();
// create new one; run it;
Srch_crt_mgr crt_mgr = crt_parser.Parse_or_invalid(qry.Phrase.Compiled, qry.Phrase.Wildcard);
if (crt_mgr == Srch_crt_mgr.Invalid) return; // handle "\\" which is invalid or other fatal errors
Srch_rslt_list rslts_list = cache__rslts.Get_or_new(crt_mgr.Key);
cur_cmd = new Srch_search_cmd(this, qry, crt_mgr, cbk, rslts_list);
cur_cmds[qry.Tid] = cur_cmd;
gplx.core.threads.Thread_adp_.invk_(gplx.xowa.apps.Xoa_thread_.Key_special_suggest, cur_cmd, Srch_search_cmd.Invk__search).Start();
}
public void Search_async(Cancelable cxl, Srch_search_qry qry, Srch_crt_mgr crt_mgr, Srch_rslt_cbk rslt_cbk, Srch_rslt_list rslts_list) {
synchronized (mutex) { // force only one search at a time; do not (a) place around Thread_sleep; (b) reuse for any other locks
if (++search_count > 64) this.Clear(); // lazy way of clearing memory
Srch_search_ctx ctx = new Srch_search_ctx(cxl, wiki, addon, cache__page, cache__word_counts, qry, Scanner_syms, crt_mgr, rslts_list);
ctx.Score_rng.Select_init(ctx.Rslts_needed, rslts_list.Score_bgn, rslts_list.Score_len, Srch_link_wkr.Percentile_rng__calc_adj(crt_mgr.Words_nth__len()));
page_tbl_searcher.Search(ctx, rslt_cbk);
if (cxl.Canceled()) return;
Srch_link_wkr link_wkr = new Srch_link_wkr();
link_wkr.Search(rslts_list, rslt_cbk, ctx);
}
}
private void Clear() {
search_count = 0;
cache__page.Clear();
cache__word_counts.Clear();
cache__rslts.Clear();
}
public static final Srch_crt_scanner_syms Scanner_syms = Srch_crt_scanner_syms.Dflt;
}

View File

@@ -0,0 +1,133 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.core.btries.*;
import gplx.xowa.addons.searchs.searchers.crts.*;
public class Srch_search_phrase {
public Srch_search_phrase(boolean wildcard, byte[] orig, byte[] compiled) {
this.Orig = orig;
this.Compiled = compiled;
this.Wildcard = wildcard;
}
public final boolean Wildcard;
public final byte[] Orig; // EX: "Earth"
public final byte[] Compiled; // EX: "earth*"
public static Srch_search_phrase New(gplx.xowa.langs.cases.Xol_case_mgr case_mgr, byte[] orig, boolean wildcard) {
int orig_len = orig.length;
if ( orig_len > 0 // if "*" at end, remove and change to wildcard; needed for Special:Search which will send in "earth*" but "earth" needed for highlighting
&& orig[orig_len - 1] == Srch_crt_scanner_syms.Dflt.Wild()) {
orig = Bry_.Mid(orig, 0, orig_len - 1);
wildcard = true;
}
byte[] lcase = case_mgr.Case_build_lower(orig);
lcase = Auto_wildcard(lcase, Srch_crt_scanner_syms.Dflt);
return new Srch_search_phrase(wildcard, orig, lcase);
}
public static byte[] Auto_wildcard(byte[] raw, Srch_crt_scanner_syms syms) {
Btrie_slim_mgr trie = syms.Trie();
int raw_len = raw.length;
int insert_pos = -1;
int fail_pos = -1;
for (int i = raw_len - 1; i > -1; --i) {
byte b = raw[i];
byte tid = trie.Match_byte_or(b, raw, i, i + 1, Byte_.Max_value_127);
if (tid == Byte_.Max_value_127) { // unknown sym
if (b == syms.Wild()) { // wildcard is not tokenized
fail_pos = i;
break;
}
else { // alphanum-char
insert_pos = i;
break;
}
}
else {
switch (tid) {
case Srch_crt_tkn.Tid__quote:
case Srch_crt_tkn.Tid__space:
case Srch_crt_tkn.Tid__not:
case Srch_crt_tkn.Tid__and:
case Srch_crt_tkn.Tid__or:
case Srch_crt_tkn.Tid__paren_bgn:
fail_pos = i; // these symbols will not auto-wildcard, unless they are escaped
i = -1;
break;
case Srch_crt_tkn.Tid__escape:
if (i > 0) {
int prv_pos = i -1;
if (raw[prv_pos] == syms.Escape()) { // an escaped escape can be wildcarded; EX: "\\" -> "\\*"
insert_pos = i;
i = -1;
}
else
fail_pos = i;
}
else
fail_pos = i;
i = -1;
break;
case Srch_crt_tkn.Tid__paren_end:
break;
}
}
}
// check if preceded by escape
if (insert_pos == -1) {
if ( fail_pos > 0
&& raw[fail_pos - 1] == syms.Escape()) {
insert_pos = fail_pos;
}
else
return raw;
}
// check if word already has wildcard; EX: "a*b" x> "a*b*"
for (int i = insert_pos - 1; i > -1; --i) {
byte b = raw[i];
if (b == syms.Wild()) {
int prv_pos = i - 1;
if (prv_pos > -1) {
if (raw[prv_pos] == syms.Escape()) { // ignore escaped wildcard
i = prv_pos;
continue;
}
}
return raw; // existing wildcard cancels auto-wildcard
}
else if (b == syms.Space()) { // stop looking when word ends
break;
}
else {} // alphanum; keep going
}
// add wildcard
if (insert_pos == raw_len - 1) return Bry_.Add(raw, syms.Wild());
else {
byte[] rv = new byte[raw_len + 1];
int wildcard_pos = insert_pos + 1;
for (int i = 0; i < wildcard_pos; ++i)
rv[i] = raw[i];
rv[wildcard_pos] = syms.Wild();
for (int i = wildcard_pos; i < raw_len; ++i)
rv[i + 1] = raw[i];
return rv;
}
}
}

View File

@@ -0,0 +1,46 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import org.junit.*; import gplx.xowa.addons.searchs.parsers.*; import gplx.xowa.addons.searchs.searchers.crts.*;
public class Srch_search_phrase_tst {
private final Srch_search_phrase_fxt fxt = new Srch_search_phrase_fxt();
@Test public void Word() {fxt.Test__auto_wildcard("a" , "a*");}
@Test public void Paren_end() {fxt.Test__auto_wildcard("(a)" , "(a*)");}
@Test public void Quoted() {fxt.Test__auto_wildcard("\"a\"" , "\"a\"");}
@Test public void Space() {fxt.Test__auto_wildcard(" " , " ");}
@Test public void Not() {fxt.Test__auto_wildcard("-" , "-");}
@Test public void And() {fxt.Test__auto_wildcard("+" , "+");}
@Test public void Or() {fxt.Test__auto_wildcard("," , ",");}
@Test public void Paren_bgn() {fxt.Test__auto_wildcard("(" , "(");}
@Test public void Star() {fxt.Test__auto_wildcard("*" , "*");}
@Test public void Wildcard__exists__y() {fxt.Test__auto_wildcard("a*b" , "a*b");}
@Test public void Wildcard__exists__escaped() {fxt.Test__auto_wildcard("a\\*b" , "a\\*b*");}
@Test public void Wildcard__exists__n() {fxt.Test__auto_wildcard("a* bc" , "a* bc*");}
@Test public void Escape() {fxt.Test__auto_wildcard("\\*" , "\\**");}
@Test public void Escape__incomplete() {fxt.Test__auto_wildcard("a\\" , "a\\");}
@Test public void Escape__escaped() {fxt.Test__auto_wildcard("a\\\\" , "a\\\\*");}
}
class Srch_search_phrase_fxt {
private final Srch_crt_scanner_syms syms = Srch_crt_scanner_syms.Dflt;
public Srch_search_phrase_fxt() {}
public void Test__auto_wildcard(String src_str, String expd) {
byte[] src_raw = Bry_.new_u8(src_str);
byte[] actl = Srch_search_phrase.Auto_wildcard(src_raw, syms);
Tfds.Eq(expd, String_.new_u8(actl));
}
}

View File

@@ -0,0 +1,50 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.xowa.wikis.domains.*;
public class Srch_search_qry {
public Srch_search_qry(byte tid, Srch_ns_mgr ns_mgr, Srch_search_phrase phrase, int slab_bgn, int slab_end) {
this.Tid = tid;
this.Ns_mgr = ns_mgr;
this.Phrase = phrase;
this.Slab_bgn = slab_bgn;
this.Slab_end = slab_end;
}
public final byte Tid;
public final Srch_ns_mgr Ns_mgr;
public final Srch_search_phrase Phrase;
public final int Slab_bgn; // EX: 0
public final int Slab_end; // EX: 20
public static final byte Tid_len = 4, Tid__url_bar = 0, Tid__suggest_box = 1, Tid__search_page = 2, Tid__android = 3;
public static Srch_search_qry New__url_bar(Xow_wiki wiki, gplx.xowa.apps.apis.xowa.addons.searchs.Xoapi_url_bar cfg, byte[] search_orig) {
return new Srch_search_qry(Tid__url_bar, cfg.Ns_mgr(), Srch_search_phrase.New(wiki.Case_mgr(), search_orig, cfg.Auto_wildcard()), 0, cfg.Max_results());
}
public static Srch_search_qry New__suggest_box(Xow_wiki wiki, Srch_search_cfg cfg, byte[] search_orig) {
return new Srch_search_qry(Tid__suggest_box, cfg.Ns_mgr(), Srch_search_phrase.New(wiki.Case_mgr(), search_orig, Bool_.Y), 0, cfg.Rslts_max());
}
public static Srch_search_qry New__search_page(Xow_domain_itm[] domains, Xow_wiki wiki, Srch_search_cfg cfg, boolean simple_search, byte[] search_orig, int slab_idx, int slab_len) {
int slab_bgn = slab_idx * slab_len;
int slab_end = slab_bgn + slab_len;
boolean wildcard = simple_search;
return new Srch_search_qry(Tid__search_page, cfg.Ns_mgr(), Srch_search_phrase.New(wiki.Case_mgr(), search_orig, wildcard), slab_bgn, slab_end);
}
public static Srch_search_qry New__drd(Xow_wiki wiki, Srch_ns_mgr ns_mgr, byte[] search_orig, int slab_bgn, int slab_end) {
return new Srch_search_qry(Tid__android, ns_mgr, Srch_search_phrase.New(wiki.Case_mgr(), search_orig, Bool_.Y), slab_bgn, slab_end);
}
}

View File

@@ -0,0 +1,57 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.cbks; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.core.js.*;
import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_rslt_cbk__suggest_box implements Srch_rslt_cbk, GfoInvkAble {
private final Js_wtr js_wtr = new Js_wtr();
private final Xoae_app app;
private final byte[] cbk_func;
private final byte[] search_raw;
public Srch_rslt_cbk__suggest_box(Xoae_app app, byte[] cbk_func, byte[] search_raw) {
this.app = app; this.cbk_func = cbk_func;
this.search_raw = search_raw;
}
public void On_cancel() {}
public void On_rslts_found(Srch_search_qry qry, Srch_rslt_list rslts_list, int rslts_bgn, int rslts_end) {
if (!rslts_list.Rslts_are_enough && !rslts_list.Rslts_are_done) return;
js_wtr.Func_init(cbk_func);
js_wtr.Prm_bry(search_raw);
js_wtr.Prm_spr();
js_wtr.Ary_init();
int rslts_len = rslts_list.Len();
for (int i = 0; i < qry.Slab_end; i++) {
if (i >= rslts_len) break; // rslts_end will overshoot actual rslts_len; check for out of bounds and exit; EX: default suggest will have rslts_end of 25, but "earth time" will retrieve 15 results
Srch_rslt_row row = rslts_list.Get_at(i);
js_wtr.Ary_bry(row.Page_ttl.Full_txt_w_ttl_case());
js_wtr.Ary_bry(row.Page_ttl_display(Bool_.Y));
}
js_wtr.Ary_term();
js_wtr.Func_term();
GfoInvkAble_.InvkCmd(app.Gui_mgr().Kit().New_cmd_sync(this), Srch_rslt_cbk__suggest_box.Invk__notify);
}
private void Notify() {
app.Gui_mgr().Browser_win().Active_html_box().Html_js_eval_script(js_wtr.To_str_and_clear());
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__notify)) Notify();
else return GfoInvkAble_.Rv_unhandled;
return this;
}
public static final String Invk__notify = "notify";
}

View File

@@ -0,0 +1,86 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.cbks; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.gfui.*;
import gplx.xowa.addons.searchs.searchers.rslts.*;
import gplx.xowa.apps.apis.xowa.addons.searchs.*;
public class Srch_rslt_cbk__url_bar implements Srch_rslt_cbk, GfoInvkAble {
private final Xoae_app app;
private final GfuiComboBox url_bar;
private final Xoapi_url_bar url_bar_api;
private String[] cbo_ary;
private boolean rslts_finished;
private int rslts_in_this_pass;
private boolean rslts_shown = false;
public Srch_rslt_cbk__url_bar(Xoae_app app, GfuiComboBox url_bar, Xoapi_url_bar url_bar_api) {
this.app = app; this.url_bar = url_bar; this.url_bar_api = url_bar_api;
}
public void On_cancel() {}
public void On_rslts_found(Srch_search_qry qry, Srch_rslt_list rslts_list, int rslts_bgn, int rslts_end) {
int rslts_len = rslts_list.Len();
this.rslts_finished = rslts_list.Rslts_are_enough || rslts_list.Rslts_are_done;
// get # of items for drop-down; note special logic to reduce blinking
rslts_in_this_pass = rslts_end - rslts_bgn;
if ( rslts_in_this_pass == 0 // no new results;
&& rslts_bgn != 0 // if first one, still update; blanks out results from previous try;
&& !rslts_finished) // if rslts_finished, still update to force cbo to "shrink"
return; // exit now else will "blink" when refreshing;
int max_rslts = url_bar_api.Max_results();
int cbo_len = max_rslts; // force cbo_len to be max_rslts; reduces "blinking" when typing by keeping visible area to same size
if (rslts_list.Rslts_are_done) { // "shrink" cbo_len to rslts_len; EX: 10 wanted; 2 returned; shrink to 2 rows;
cbo_len = rslts_len;
}
// fill cbo_ary with rslts from search, while "blanking" out rest
this.cbo_ary = new String[cbo_len];
for (int i = 0; i < cbo_len; ++i) {
String cbo_itm = "";
if (i >= max_rslts) break;
if (i < rslts_len) {
Srch_rslt_row rslt = rslts_list.Get_at(i);
cbo_itm = String_.new_u8(rslt.Page_ttl_display(Bool_.N));
}
cbo_ary[i] = cbo_itm;
}
GfoInvkAble_.InvkCmd(app.Gui_mgr().Kit().New_cmd_sync(this), Srch_rslt_cbk__url_bar.Invk__items__update); // NOTE: needs to be sync, b/c page_wkr and link_wkr must execute in order; EX:"Portal:Science" does not show; DATE:2016-03-24
}
private void Items__update() {
url_bar.Items__update(cbo_ary);
if (!url_bar.List_visible() // rslt_list not visible
&& !rslts_shown // auto-dropdown hasn't happened yet
&& (rslts_in_this_pass > 0 || rslts_finished) // at least 1 rslt, or search done
) {
rslts_shown = true; // only auto-show dropdown once; allows user to close drop-down and not have it continually flashing
url_bar.List_visible_(Bool_.Y);
}
Xoa_app_.Usr_dlg().Prog_none("", "", "");
if (rslts_finished) {
if (cbo_ary.length == 0)
url_bar.List_visible_(Bool_.N);
else
url_bar.Items__size_to_fit(cbo_ary.length);
}
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__items__update)) Items__update();
else return GfoInvkAble_.Rv_unhandled;
return this;
} private static final String Invk__items__update = "items__update";
}

View File

@@ -0,0 +1,51 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//namespace gplx.xowa.addons.searchs.searchers.cbks {
// class Srch_suggest_cmd__page_tbl {
// private boolean Search_by_all_pages_v2() {
// rslts_2.Clear();
// Xoa_ttl search_ttl = Xoa_ttl.parse(wiki, search_bry); if (search_ttl == null) return false;
// byte[] search_ttl_bry = search_ttl.Page_db();
// wiki.Db_mgr().Load_mgr().Load_ttls_for_search_suggest(this, rslts_2, search_ttl.Ns(), search_ttl_bry, max_results, all_pages_min, all_pages_extend, true, false);
// return true;
// }
// private boolean Search_by_all_pages_v1() {
// rslts_2.Clear();
// Xowd_page_itm rslt_nxt = new Xowd_page_itm();
// Xowd_page_itm rslt_prv = new Xowd_page_itm();
// Xoa_ttl search_ttl = Xoa_ttl.parse(wiki, search_bry); if (search_ttl == null) return false;
// byte[] search_ttl_bry = search_ttl.Page_db();
// List_adp page_list = List_adp_.new_();
// wiki.Db_mgr().Load_mgr().Load_ttls_for_all_pages(this, page_list, rslt_nxt, rslt_prv, Int_obj_ref.zero_(), wiki.Ns_mgr().Ns_main(), search_ttl_bry, max_results, all_pages_min, all_pages_extend, true, false);
// Xowd_page_itm[] page_ary = (Xowd_page_itm[])page_list.To_ary_and_clear(typeof(Xowd_page_itm));
// int idx = 0, page_ary_len = page_ary.length;
// for (int i = 0; i < page_ary_len; i++) {
// Xowd_page_itm page = page_ary[i];
// if (page != null) {
// if (!Bry_.Has_at_bgn(page.Ttl_page_db(), search_ttl_bry)) continue; // look-ahead may return other titles that don't begin with search; ignore
// if (page.Text_len() > all_pages_min) {
// rslts_2.Add(page);
// idx++;
// }
// }
// if (idx == max_results) break;
// }
// return true;
// }
// }
//}

View File

@@ -0,0 +1,48 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.langs.regxs.*;
public class Srch_crt_itm {
public Srch_crt_itm(int idx, int tid, Srch_crt_itm[] subs, byte[] raw, Srch_crt_sql raw_data) {
this.Idx = idx; this.Tid = tid; this.Subs = subs;
this.Raw = raw;
this.Sql_data = raw_data;
}
public final int Idx; // itm index; EX: "a b" -> a:0 b:1
public final int Tid;
public final byte[] Raw;
public final Srch_crt_itm[] Subs;
public final Srch_crt_sql Sql_data;
public void Accept_visitor(Srch_crt_visitor visitor) {visitor.Visit(this);}
public static final int
Tid__word = 0 // EX: 'A'
, Tid__and = 1 // EX: 'A B'
, Tid__or = 2 // EX: 'A OR B'
, Tid__not = 3 // EX: '-A'
, Tid__word_quote = 4 // EX: '"A B"'
, Tid__invalid = 5 // EX: 'A OR'; incomplete or otherwise invalid
;
public static Srch_crt_itm[] Ary_empty = new Srch_crt_itm[0];
public static final Srch_crt_itm Invalid = new Srch_crt_itm(-1, Srch_crt_itm.Tid__invalid, Srch_crt_itm.Ary_empty, null, null);
public static Srch_crt_itm New_join(int tid, int idx, Srch_crt_itm... ary) {return new Srch_crt_itm(idx, tid, ary, null, Srch_crt_sql.New_or_null(null, Byte_ascii.Null));}
public static Srch_crt_itm New_word(byte wildcard_byte, Srch_crt_tkn tkn, int idx, byte[] src) {
int tid = tkn.Tid == Srch_crt_tkn.Tid__word_w_quote ? Srch_crt_itm.Tid__word_quote : Srch_crt_itm.Tid__word;
return new Srch_crt_itm(idx, tid, Srch_crt_itm.Ary_empty, tkn.Val, Srch_crt_sql.New_or_null(src, wildcard_byte));
}
}

View File

@@ -0,0 +1,44 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
public class Srch_crt_mgr {
public Srch_crt_mgr(byte[] key, Srch_crt_tkn[] tkns, Srch_crt_itm root, byte words_tid, Srch_crt_itm[] words_ary, Srch_crt_itm words_nth) {
this.Key = key;
this.Tkns = tkns;
this.Root = root;
this.Words_tid = words_tid;
this.Words_ary = words_ary;
this.Words_nth = words_nth;
}
public final byte[] Key;
public final Srch_crt_tkn[] Tkns;
public final Srch_crt_itm Root;
public final byte Words_tid;
public final Srch_crt_itm[] Words_ary;
public final Srch_crt_itm Words_nth;
public int Words_nth__len() {
return Words_nth == null ? 0 : Words_nth.Raw.length;
}
public static final byte
Tid__one = 0
, Tid__ands = 1
, Tid__mixed = 2
;
public static Srch_crt_mgr Invalid = new Srch_crt_mgr(Bry_.Empty, Srch_crt_tkn.Ary_empty, Srch_crt_itm.Invalid, Tid__one, Srch_crt_itm.Ary_empty, Srch_crt_itm.Invalid);
}

View File

@@ -0,0 +1,146 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.xowa.addons.searchs.searchers.crts.visitors.*;
public class Srch_crt_parser {
private final Srch_crt_scanner scanner;
private final Srch_crt_visitor__words words_visitor = new Srch_crt_visitor__words();
private final Srch_crt_visitor__print print_visitor = new Srch_crt_visitor__print();
private final byte wildcard_byte;
private int uid_next;
public Srch_crt_parser(Srch_crt_scanner_syms trie_bldr) {
this.wildcard_byte = trie_bldr.Wild();
this.scanner = new Srch_crt_scanner(trie_bldr);
}
public int Next_uid() {return ++uid_next;}
public Srch_crt_mgr Parse_or_invalid(byte[] src, boolean auto_wildcard) {
this.uid_next = -1;
Srch_crt_tkn[] tkns_ary = scanner.Scan(src);
Srch_crt_parser_frame root_frame = new Srch_crt_parser_frame(this);
Parse_tkns(root_frame, tkns_ary, 0, tkns_ary.length);
Srch_crt_itm root_itm = root_frame.Produce_or_null();
if (root_itm == null) return Srch_crt_mgr.Invalid;
byte[] key = print_visitor.Print(root_itm);
words_visitor.Gather(root_itm);
return new Srch_crt_mgr(key, tkns_ary, root_itm, words_visitor.Words_tid(), words_visitor.Words_ary(), words_visitor.Words_nth());
}
private int Parse_tkns(Srch_crt_parser_frame frame, Srch_crt_tkn[] tkns_ary, int tkns_bgn, int tkns_end) {
int tkns_cur = tkns_bgn;
while (tkns_cur < tkns_end) {
Srch_crt_tkn cur_tkn = tkns_ary[tkns_cur];
int new_tkns_cur = Process_tkn(frame, tkns_ary, tkns_cur, tkns_end, cur_tkn);
if (new_tkns_cur < 0) {
tkns_cur = -new_tkns_cur;
break;
}
else
tkns_cur = new_tkns_cur;
}
return tkns_cur;
}
private int Process_tkn(Srch_crt_parser_frame frame, Srch_crt_tkn[] tkns_ary, int tkns_cur, int tkns_end, Srch_crt_tkn cur_tkn) {
byte cur_tid = cur_tkn.Tid;
switch (cur_tid) {
case Srch_crt_tkn.Tid__word:
case Srch_crt_tkn.Tid__word_w_quote:
frame.Subs__add(Srch_crt_itm.New_word(wildcard_byte, cur_tkn, frame.Next_uid(), cur_tkn.Val));
break;
case Srch_crt_tkn.Tid__and:
frame.Eval_join(Srch_crt_itm.Tid__and);
break;
case Srch_crt_tkn.Tid__or:
frame.Eval_join(Srch_crt_itm.Tid__or);
break;
case Srch_crt_tkn.Tid__paren_bgn: {
Srch_crt_parser_frame paren_frame = new Srch_crt_parser_frame(this);
int new_tkns_cur = Parse_tkns(paren_frame, tkns_ary, tkns_cur + 1, tkns_end);
Srch_crt_itm paren_itm = paren_frame.Produce_or_null();
if (paren_itm != null) {
frame.Subs__add(paren_itm);
}
return new_tkns_cur;
}
case Srch_crt_tkn.Tid__paren_end:
return -(tkns_cur + 1);
case Srch_crt_tkn.Tid__not:
frame.Notted_y_();
break;
}
return tkns_cur + 1;
}
}
class Srch_crt_parser_frame {
public Srch_crt_parser_frame(Srch_crt_parser parser) {
this.parser = parser;
}
private int join_tid = Srch_crt_tkn.Tid__null;
private boolean notted = false;
private final List_adp subs = List_adp_.new_();
private final Srch_crt_parser parser;
public int Next_uid() {return parser.Next_uid();}
public void Notted_y_() {
if (notted) // already notted; disable; EX: "--a"
notted = false;
else
notted = true;
}
public void Subs__add(Srch_crt_itm itm) {
// if notted, wrap itm in not; EX: "-a"; "-(a & b)"
if (notted) {
itm = Srch_crt_itm.New_join(Srch_crt_itm.Tid__not, this.Next_uid(), itm);
notted = false;
}
subs.Add(itm);
// auto-and behavior; EX: "a b" -> "a & b"; EX: "a (b | c)" -> "a & (b | c)"
if ( join_tid == Srch_crt_tkn.Tid__null // if currently null
&& subs.Len() > 1 // but 2 items in list
)
join_tid = Srch_crt_itm.Tid__and; // default to AND; EX: "a (b) c"
}
public void Eval_join(int tid) {
if (join_tid == Srch_crt_tkn.Tid__null) join_tid = tid;
else if (join_tid == tid) {} // tid is same; ignore; note that this handles dupes; EX: "a & & b"
else { // tid changed; EX: a & b | c
Merge_and_add();
join_tid = tid;
}
}
public Srch_crt_itm Produce_or_null() {
int subs_len = subs.Len();
switch (subs_len) {
case 0:
return null;
case 1:
join_tid = Srch_crt_tkn.Tid__null;
return (Srch_crt_itm)subs.Get_at(0);
default:
Srch_crt_itm[] subs_ary = (Srch_crt_itm[])subs.To_ary_and_clear(Srch_crt_itm.class);
Srch_crt_itm rv = Srch_crt_itm.New_join(join_tid, parser.Next_uid(), subs_ary);
join_tid = Srch_crt_tkn.Tid__null;
return rv;
}
}
private void Merge_and_add() {
int subs_len = subs.Len();
if (subs_len > 1)
subs.Add(Produce_or_null());
}
}

View File

@@ -0,0 +1,68 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import org.junit.*; import gplx.xowa.addons.searchs.parsers.*; import gplx.xowa.addons.searchs.searchers.crts.visitors.*;
public class Srch_crt_parser_tst {
private final Srch_crt_parser_fxt fxt = new Srch_crt_parser_fxt();
@Test public void Word__one() {fxt.Test__parse("a" , "a");}
@Test public void And__one() {fxt.Test__parse("a + b" , "(a AND b)");}
@Test public void And__many() {fxt.Test__parse("a + b + c" , "(a AND b AND c)");}
@Test public void And__dangling() {fxt.Test__parse("a +" , "a");}
@Test public void And__dupe() {fxt.Test__parse("a + + b" , "(a AND b)");}
@Test public void Quote() {fxt.Test__parse("\"a b\"" , "\"a b\"");}
@Test public void Auto__word() {fxt.Test__parse("a b" , "(a AND b)");}
@Test public void Auto__quote() {fxt.Test__parse("a \"b\"" , "(a AND \"b\")");}
@Test public void Auto__parens() {fxt.Test__parse("a (b , c)" , "(a AND (b OR c))");}
@Test public void Or__one() {fxt.Test__parse("a , b" , "(a OR b)");}
@Test public void Or__many() {fxt.Test__parse("a , b , c" , "(a OR b OR c)");}
@Test public void Mixed__3() {fxt.Test__parse("a + b , c" , "((a AND b) OR c)");}
@Test public void Mixed__5() {fxt.Test__parse("a + b , c + d , e" , "((((a AND b) OR c) AND d) OR e)");}
@Test public void Parens__basic() {fxt.Test__parse("a + (b , c)" , "(a AND (b OR c))");}
@Test public void Parens__nest() {fxt.Test__parse("a + (b , (c + d))" , "(a AND (b OR (c AND d)))");}
@Test public void Parens__mid() {fxt.Test__parse("a + (b , c) + d)" , "(a AND (b OR c) AND d)");}
@Test public void Parens__mixed() {fxt.Test__parse("a + (b , c) , d)" , "((a AND (b OR c)) OR d)");}
@Test public void Parens__dupe() {fxt.Test__parse("((a))" , "a");}
@Test public void Parens__dangling__lhs() {fxt.Test__parse("(a" , "a");}
@Test public void Parens__dangling__rhs() {fxt.Test__parse("a)" , "a");}
@Test public void Parens__empty__bos() {fxt.Test__parse("()" , "");}
@Test public void Parens__empty__mid() {fxt.Test__parse("a () b" , "(a AND b)");}
@Test public void Not__bos() {fxt.Test__parse("-abc" , "NOT abc");}
@Test public void Not__mid() {fxt.Test__parse("a -b" , "(a AND NOT b)");}
@Test public void Not__2() {fxt.Test__parse("a -b -c" , "(a AND NOT b AND NOT c)");}
@Test public void Not__dangling__eos() {fxt.Test__parse("a -" , "a");}
@Test public void Not__dangling__mid() {fxt.Test__parse("a -- b" , "(a AND b)");} // NOTE: scanner will remove spaces and convert to "a", "--", "b"
@Test public void Not__dupe__2() {fxt.Test__parse("a --b" , "(a AND b)");}
@Test public void Not__dupe__3() {fxt.Test__parse("a ---b" , "(a AND NOT b)");}
@Test public void Not__parens() {fxt.Test__parse("a -(b + c)" , "(a AND NOT (b AND c))");}
@Test public void Escape__eos() {fxt.Test__parse("\\" , "");}
@Test public void Escape__escaped() {fxt.Test__parse("\\\\*" , "\\*");} // '\\' -> '\*'
}
class Srch_crt_parser_fxt {
private final Srch_crt_parser crt_parser;
private final Srch_crt_visitor__print visitor__to_str = new Srch_crt_visitor__print();
public Srch_crt_parser_fxt() {
crt_parser = new Srch_crt_parser(Srch_crt_scanner_syms.Dflt);
Srch_text_parser text_parser = new Srch_text_parser();
text_parser.Init_for_ttl(gplx.xowa.langs.cases.Xol_case_mgr_.A7());
}
public void Test__parse(String src_str, String expd) {
byte[] src_bry = Bry_.new_a7(src_str);
Srch_crt_mgr crt_mgr = crt_parser.Parse_or_invalid(src_bry, Bool_.N);
Tfds.Eq(expd, String_.new_u8(visitor__to_str.Print(crt_mgr.Root)));
}
}

View File

@@ -0,0 +1,136 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.core.btries.*; import gplx.xowa.langs.cases.*;
import gplx.xowa.addons.searchs.parsers.*;
class Srch_crt_scanner {
private final List_adp tkns = List_adp_.new_(); private byte[] src; private int src_len, pos, txt_bgn;
private final Srch_crt_scanner_syms trie_bldr; private final Btrie_slim_mgr trie;
private final Bry_bfr word_bfr = Bry_bfr.new_(); private boolean word_is_dirty;
public Srch_crt_scanner(Srch_crt_scanner_syms trie_bldr) {
this.trie_bldr = trie_bldr;
this.trie = trie_bldr.Trie();
}
public Srch_crt_tkn[] Scan(byte[] src) {
this.src = src; this.src_len = src.length;
tkns.Clear(); pos = 0; txt_bgn = -1;
while (pos < src_len) {
byte cur_b = src[pos];
byte cur_tid = trie.Match_byte_or(cur_b, src, pos, src_len, Byte_.Max_value_127);
if (cur_tid == Byte_.Max_value_127) { // text character
if (txt_bgn == -1) txt_bgn = pos; // 1st character not set; set it
if (word_is_dirty) word_bfr.Add_byte(cur_b);
++pos;
}
else { // \ \s " - & | ( )
int pos_end = trie.Match_pos();
if ( cur_tid == Srch_crt_tkn.Tid__not // if "-"
&& txt_bgn != -1) { // && "word has started"
++pos;
continue; // ignore; EX: "a-b" -> "a-b"; "-ab" -> "NOT" "ab"
}
if ( txt_bgn != -1 // pending word
&& cur_tid != Srch_crt_tkn.Tid__escape // not escape
) {
Add_word(Srch_crt_tkn.Tid__word, txt_bgn, pos);
}
switch (cur_tid) {
case Srch_crt_tkn.Tid__escape: // handle escape
int nxt_pos = pos + 1;
if (txt_bgn == -1) {
txt_bgn = nxt_pos;
word_is_dirty = true;
} else { // word has started; transfer existing word to bfr;
if (!word_is_dirty) {
word_is_dirty = true;
word_bfr.Add_mid(src, txt_bgn, pos);
}
}
pos = nxt_pos; // skip "\"
if (pos < src_len) {
word_bfr.Add_byte(src[pos]); // add next char literally
++pos;
}
break;
case Srch_crt_tkn.Tid__space: // discard spaces
pos = Bry_find_.Find_fwd_while(src, pos, src_len, trie_bldr.Space());
break;
case Srch_crt_tkn.Tid__quote: // find end quote and add as word
int quote_bgn = pos + 1;
int quote_end = Int_.Min_value;
int tmp_pos = quote_bgn;
while (true) {
quote_end = Bry_find_.Find_fwd(src, trie_bldr.Quote(), tmp_pos, src_len);
if (quote_end == Bry_find_.Not_found) { // no end-quote found; use space
quote_end = Bry_find_.Find_fwd(src, trie_bldr.Space(), quote_bgn, src_len);
if (quote_end == Bry_find_.Not_found) quote_end = src_len; // no space found; use EOS
}
else { // end-quote found; check if it's doubled
int double_pos = quote_end + 1;
if ( double_pos < src_len
&& src[double_pos] == Byte_ascii.Quote) {
if (!word_is_dirty) {
word_is_dirty = true;
}
word_bfr.Add_mid(src, tmp_pos, double_pos);
tmp_pos = double_pos + 1;
continue;
}
}
break;
}
if (word_is_dirty)
word_bfr.Add_mid(src, tmp_pos, quote_end);
Add_word(Srch_crt_tkn.Tid__word_w_quote, quote_bgn, quote_end);
pos = quote_end + 1; // +1 to place after quote
break;
case Srch_crt_tkn.Tid__not:
Add_word(Srch_crt_tkn.Tid__not, pos, pos_end);
pos = pos_end;
break;
case Srch_crt_tkn.Tid__paren_bgn: case Srch_crt_tkn.Tid__paren_end:
case Srch_crt_tkn.Tid__and: case Srch_crt_tkn.Tid__or:
tkns.Add(New_tkn(cur_tid, Bry_.Mid(src, pos, pos_end)));
pos = pos_end;
break;
default: throw Err_.new_unhandled_default(cur_tid);
}
}
}
if (txt_bgn != -1) { // pending word; create
Add_word(Srch_crt_tkn.Tid__word, txt_bgn, pos);
}
return (Srch_crt_tkn[])tkns.To_ary_and_clear(Srch_crt_tkn.class);
}
private void Add_word(byte tid, int src_bgn, int src_end) {
// generate word_bry
byte[] word_bry = null;
if (word_is_dirty) {
word_is_dirty = false;
if (word_bfr.Len_eq_0()) return;
word_bry = word_bfr.To_bry_and_clear();
}
else {
if (src_end - src_bgn == 0) return;
word_bry = Bry_.Mid(src, src_bgn, src_end);
}
tkns.Add(New_tkn(tid, word_bry));
txt_bgn = -1;
}
private static Srch_crt_tkn New_tkn(byte tid, byte[] val) {return new Srch_crt_tkn(tid, val);}
}

View File

@@ -0,0 +1,112 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.core.btries.*;
public class Srch_crt_scanner_syms {
public Srch_crt_scanner_syms(byte escape, byte space, byte quote, byte not, byte and, byte or, byte paren_bgn, byte paren_end, byte wild) {
this.escape = escape; this.space = space; this.quote = quote;
this.not = not; this.and = and; this.and_bry = Bry_.New_by_byte(and); this.or = or;
this.paren_bgn = paren_bgn; this.paren_end = paren_end;
this.wild = wild;
this.trie = Btrie_slim_mgr.cs();
Make_trie(trie, this);
}
public byte Escape() {return escape;} private byte escape;
public byte Space() {return space;} private byte space;
public byte Quote() {return quote;} private byte quote;
public byte Not() {return not;} private byte not;
public byte And() {return and;} private byte and;
public byte[] And_bry() {return and_bry;} private byte[] and_bry;
public byte Or() {return or;} private byte or;
public byte Paren_bgn() {return paren_bgn;} private byte paren_bgn;
public byte Paren_end() {return paren_end;} private byte paren_end;
public byte Wild() {return wild;} private byte wild;
public Btrie_slim_mgr Trie() {return trie;} private final Btrie_slim_mgr trie;
public byte[] To_bry() {
Bry_bfr bfr = Bry_bfr.new_();
To_bry__add(bfr, "wild" , wild);
To_bry__add(bfr, "not" , not);
To_bry__add(bfr, "or" , or);
To_bry__add(bfr, "and" , and);
To_bry__add(bfr, "quote" , quote);
To_bry__add(bfr, "paren_bgn" , paren_bgn);
To_bry__add(bfr, "paren_end" , paren_end);
To_bry__add(bfr, "escape" , escape);
To_bry__add(bfr, "space" , space);
return bfr.To_bry_and_clear();
}
public void Parse(byte[] src) {
byte[][] lines = Bry_split_.Split_lines(src);
escape = space = quote = not = and = or = paren_bgn = paren_end = wild = Byte_.Zero;
for (byte[] line : lines) {
int line_len = line.length;
int eq_pos = Bry_find_.Find_fwd(line, Byte_ascii.Eq, 0, line_len); if (eq_pos == Bry_find_.Not_found) continue;
String key = String_.new_u8(Bry_.Mid(line, 0, eq_pos));
byte val = Parse__val(line, eq_pos + 1, line_len);
if (String_.Eq(key, "wild" )) wild = val;
else if (String_.Eq(key, "not" )) not = val;
else if (String_.Eq(key, "or" )) or = val;
else if (String_.Eq(key, "and" )) and = val;
else if (String_.Eq(key, "quote" )) quote = val;
else if (String_.Eq(key, "paren_bgn" )) paren_bgn = val;
else if (String_.Eq(key, "paren_end" )) paren_end = val;
else if (String_.Eq(key, "escape" )) escape = val;
else if (String_.Eq(key, "space" )) space = val;
}
}
private static void To_bry__add(Bry_bfr bfr, String key, byte val) {
bfr.Add_str_u8(key).Add_byte_eq();
switch (val) {
case Byte_ascii.Null : bfr.Add_str_a7("\\0"); break;
case Byte_ascii.Space : bfr.Add_str_a7("\\s"); break;
default : bfr.Add_byte(val); break;
}
bfr.Add_byte_nl();
}
private static void Make_trie(Btrie_slim_mgr trie, Srch_crt_scanner_syms bldr) {
Make_trie__add(trie, bldr.Escape() , Srch_crt_tkn.Tid__escape);
Make_trie__add(trie, bldr.Space() , Srch_crt_tkn.Tid__space);
Make_trie__add(trie, bldr.Quote() , Srch_crt_tkn.Tid__quote);
Make_trie__add(trie, bldr.Not() , Srch_crt_tkn.Tid__not);
Make_trie__add(trie, bldr.And() , Srch_crt_tkn.Tid__and);
Make_trie__add(trie, bldr.Or() , Srch_crt_tkn.Tid__or);
Make_trie__add(trie, bldr.Paren_bgn() , Srch_crt_tkn.Tid__paren_bgn);
Make_trie__add(trie, bldr.Paren_end() , Srch_crt_tkn.Tid__paren_end);
}
private static void Make_trie__add(Btrie_slim_mgr rv, byte b, byte tid) {
if (b == Byte_ascii.Null) return;
rv.Add_bry_byte(b, tid);
}
public static final Srch_crt_scanner_syms Dflt =
new Srch_crt_scanner_syms
( Byte_ascii.Backslash, Byte_ascii.Space, Byte_ascii.Quote, Byte_ascii.Dash, Byte_ascii.Plus, Byte_ascii.Comma
, Byte_ascii.Paren_bgn, Byte_ascii.Paren_end, Byte_ascii.Star
);
private static byte Parse__val(byte[] line, int val_bgn, int line_len) {
if (line_len - val_bgn == 1) return line[val_bgn];
if ( line_len - val_bgn == 2
&& line[val_bgn] == Byte_ascii.Backslash) {
byte val_byte = line[val_bgn + 1];
switch (val_byte) {
case Byte_ascii.Num_0: return Byte_ascii.Null;
case Byte_ascii.Ltr_s: return Byte_ascii.Space;
}
}
return Byte_ascii.Null;
}
}

View File

@@ -0,0 +1,85 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import org.junit.*; import gplx.xowa.addons.searchs.parsers.*;
public class Srch_crt_scanner_tst {
private final Srch_crt_scanner_fxt fxt = new Srch_crt_scanner_fxt();
@Test public void Word() {fxt.Test__scan("abc" , "abc");}
@Test public void Word__many() {fxt.Test__scan("abc d ef" , "abc", "d", "ef");}
@Test public void Word__symbol() {fxt.Test__scan("a; b" , "a;", "b");}
@Test public void And() {fxt.Test__scan("a + b" , "a", "+", "b");}
@Test public void And__parens() {fxt.Test__scan("a +(b)" , "a", "+", "(", "b", ")");} // check that ( causes and to be treated as separate word
@Test public void Or() {fxt.Test__scan("a , b" , "a", ",", "b");}
@Test public void Or__no_space() {fxt.Test__scan("a, b" , "a", ",", "b");}
@Test public void Not() {fxt.Test__scan("-abc" , "-", "abc");}
@Test public void Not__mid__1() {fxt.Test__scan("a-b" , "a-b");} // fails if "a", "-", "b"
@Test public void Not__mid__2() {fxt.Test__scan("a b-c" , "a", "b-c");} // ignore - if in middle of word
@Test public void Not__and() {fxt.Test__scan("a -bc" , "a", "-", "bc");} // auto-add AND for -
@Test public void Not__dangling() {fxt.Test__scan("a -" , "a", "-");}
@Test public void Space() {fxt.Test__scan(" a b " , "a", "b");} // spaces should not generate tkns
@Test public void Quote() {fxt.Test__scan("\"a b\"" , "a b");}
@Test public void Quote__mid() {fxt.Test__scan("a\"b" , "a", "b");}
@Test public void Quote__double() {fxt.Test__scan("\"a\"\"b\"" , "a\"b");}
@Test public void Quote__missing__one() {fxt.Test__scan("\"abc" , "abc");}
@Test public void Quote__missing__many() {fxt.Test__scan("\"abc a" , "abc", "a");}
@Test public void Escape__bgn() {fxt.Test__scan("\\-a" , "-a");} // fails if "-", "a"
@Test public void Escape__and__bgn() {fxt.Test__scan("\\+" , "+");} // fails if "a", "&", "b"
@Test public void Escape__and__mid() {fxt.Test__scan("a\\+b" , "a+b");} // fails if "a", "&", "b"
@Test public void Escape__eos__1() {fxt.Test__scan("\\" , String_.Ary_empty);}
@Test public void Escape__eos__2() {fxt.Test__scan("a \\" , "a");}
@Test public void Escape__eos__3() {fxt.Test__scan("a\\" , "a");}
@Test public void Escape__many() {fxt.Test__scan("c\\+\\+" , "c++");}
@Test public void Escape__end() {fxt.Test__scan("a\\\\" , "a\\");}
@Test public void Complicated() {fxt.Test__scan("(a + \"b\") , -c", "(", "a", "+", "b", ")", ",", "-", "c");}
}
class Srch_crt_scanner_fxt {
private final Srch_crt_scanner scanner;
public Srch_crt_scanner_fxt() {
this.scanner = new Srch_crt_scanner(Srch_crt_scanner_syms.Dflt);
Srch_text_parser text_parser = new Srch_text_parser();
text_parser.Init_for_ttl(gplx.xowa.langs.cases.Xol_case_mgr_.A7());
}
public void Test__scan(String src_str, String... expd) {
byte[] src_bry = Bry_.new_a7(src_str);
Srch_crt_tkn[] actl_itms = scanner.Scan(src_bry);
Tfds.Eq_ary(expd, To_vals(src_bry, actl_itms));
}
public void Test__scan_tids(String src_str, byte... expd) {
byte[] src_bry = Bry_.new_a7(src_str);
Srch_crt_tkn[] actl_itms = scanner.Scan(src_bry);
Tfds.Eq_ary(expd, To_tids(actl_itms));
}
private String[] To_vals(byte[] src, Srch_crt_tkn[] ary) {
int len = ary.length;
String[] rv = new String[len];
for (int i = 0; i < len; i++) {
Srch_crt_tkn tkn = ary[i];
rv[i] = String_.new_a7(tkn.Val);
}
return rv;
}
private byte[] To_tids(Srch_crt_tkn[] ary) {
int len = ary.length;
byte[] rv = new byte[len];
for (int i = 0; i < len; i++) {
Srch_crt_tkn tkn = ary[i];
rv[i] = tkn.Tid;
}
return rv;
}
}

View File

@@ -0,0 +1,76 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.langs.regxs.*;
public class Srch_crt_sql {
public Srch_crt_sql(int tid, String eq, String rng_bgn, String rng_end, String like, Gfo_pattern pattern) {
this.Tid = tid;
this.Eq = eq;
this.Rng_bgn = rng_bgn;
this.Rng_end = rng_end;
this.Like = like;
this.Pattern = pattern;
}
public final int Tid;
public final String Eq;
public final String Rng_bgn;
public final String Rng_end;
public final String Like;
public final Gfo_pattern Pattern; // NOTE: only supports LIKE; GLOB requires regex
public int Eq_id;
public static final int
Tid__eq = 0 // EX: 'ab' -> "word_text = 'ab'"
, Tid__rng = 1 // EX: 'ab*' -> "word_text >= 'ab' AND word_text < 'ac'"
, Tid__like = 2 // EX: 'a*b', '*a*b'-> "word_text LIKE 'a%b%'"
;
public static Srch_crt_sql New_or_null(byte[] raw, byte wildcard_byte) {
if (raw == null) return null; // null for join itms; EX: "+", ","
int raw_len = raw.length;
// get tid
int wildcard_pos = Bry_find_.Find_fwd(raw, wildcard_byte, 0, raw_len);
int tid = -1;
if (wildcard_pos == Bry_find_.Not_found) tid = Srch_crt_sql.Tid__eq; // EX: 'a'
else if (wildcard_pos == raw_len - 1) tid = Srch_crt_sql.Tid__rng; // EX: 'a*'
else tid = Srch_crt_sql.Tid__like; // EX: '*a'
// get rng_bgn, rng_end or like
String eq = "", rng_bgn = "", rng_end = "", like = "";
byte[] pattern_raw = raw;
switch (tid) {
case Srch_crt_sql.Tid__eq:
eq = String_.new_a7(raw);
break;
case Srch_crt_sql.Tid__rng:
byte[] rng_tmp = Bry_.Mid(raw, 0, raw_len - 1);
rng_bgn = String_.new_u8(rng_tmp);
rng_end = String_.new_u8(gplx.core.intls.Utf8_.Increment_char_at_last_pos(rng_tmp));
break;
case Srch_crt_sql.Tid__like:
like = String_.new_u8(Bry_.Replace(raw, wildcard_byte, gplx.dbs.sqls.Sql_qry_wtr_.Like_wildcard));
byte like_escape_byte = gplx.xowa.addons.searchs.searchers.wkrs.Srch_link_wkr_sql.Like_escape_byte;
Bry_bfr tmp_bfr = Bry_bfr_.Get();
try {pattern_raw = Bry_.Resolve_escape(tmp_bfr, like_escape_byte, raw, 0, raw.length);}
finally {tmp_bfr.Mkr_rls();}
break;
}
Gfo_pattern pattern = tid == Srch_crt_sql.Tid__eq ? null : new Gfo_pattern(pattern_raw);
return new Srch_crt_sql(tid, eq, rng_bgn, rng_end, like, pattern);
}
}

View File

@@ -0,0 +1,40 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import org.junit.*;
public class Srch_crt_sql_tst {
private final Srch_crt_sql_fxt fxt = new Srch_crt_sql_fxt();
@Test public void Eq() {fxt.Exec__new_or_null("a").Test__tid(Srch_crt_sql.Tid__eq).Test__eq("a");}
@Test public void Rng() {fxt.Exec__new_or_null("a*").Test__tid(Srch_crt_sql.Tid__rng).Test__rng_bgn("a").Test__rng_end("b").Test__pattern("a*");}
@Test public void Like() {fxt.Exec__new_or_null("a*b").Test__tid(Srch_crt_sql.Tid__like).Test__like("a%b").Test__pattern("a*b");}
@Test public void Like__escape() {fxt.Exec__new_or_null("a|\\*b").Test__tid(Srch_crt_sql.Tid__like).Test__like("a|\\%b").Test__pattern("a\\*b");} // "a\*b"
@Test public void Quote() {fxt.Exec__new_or_null("\"a b\"").Test__tid(Srch_crt_sql.Tid__eq).Test__eq("\"a b\"");}
}
class Srch_crt_sql_fxt {
private Srch_crt_sql actl;
public Srch_crt_sql_fxt Exec__new_or_null(String src_str) {
this.actl = Srch_crt_sql.New_or_null(Bry_.new_u8(src_str), Srch_search_addon.Wildcard__star);
return this;
}
public Srch_crt_sql_fxt Test__tid(int expd) {Tfds.Eq(expd, actl.Tid); return this;}
public Srch_crt_sql_fxt Test__eq(String expd) {Tfds.Eq(expd, actl.Eq); return this;}
public Srch_crt_sql_fxt Test__rng_bgn(String expd) {Tfds.Eq(expd, actl.Rng_bgn); return this;}
public Srch_crt_sql_fxt Test__rng_end(String expd) {Tfds.Eq(expd, actl.Rng_end); return this;}
public Srch_crt_sql_fxt Test__like(String expd) {Tfds.Eq(expd, actl.Like); return this;}
public Srch_crt_sql_fxt Test__pattern(String expd) {Tfds.Eq(expd, String_.new_u8(actl.Pattern.Raw()), "pattern"); return this;}
}

View File

@@ -0,0 +1,38 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
public class Srch_crt_tkn {
public Srch_crt_tkn(byte tid, byte[] val) {this.Tid = tid; this.Val = val;}
public final byte Tid;
public final byte[] Val;
public static final byte
Tid__escape = 0
, Tid__space = 1
, Tid__quote = 2
, Tid__not = 3
, Tid__and = 4
, Tid__or = 5
, Tid__paren_bgn = 6
, Tid__paren_end = 7
, Tid__word = 8
, Tid__word_w_quote = 9
, Tid__eos = 10
, Tid__null = 11
;
public static final Srch_crt_tkn[] Ary_empty = new Srch_crt_tkn[0];
}

View File

@@ -15,8 +15,7 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.drds; import gplx.*; import gplx.xowa.*;
import gplx.xowa.specials.search.*;
public interface Xod_search_cmd {
void Search(Cancelable cancelable, Srch_rslt_lnr rslt_lnr, Xow_wiki wiki, String search);
package gplx.xowa.addons.searchs.searchers.crts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
public interface Srch_crt_visitor {
void Visit(Srch_crt_itm node);
}

View File

@@ -0,0 +1,49 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts.visitors; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.searchers.crts.*;
public class Srch_crt_visitor__print implements Srch_crt_visitor {
private final Bry_bfr bfr = Bry_bfr.new_();
public byte[] Print(Srch_crt_itm root) {
Visit(root);
return bfr.To_bry_and_clear();
}
public void Visit(Srch_crt_itm node) {
switch (node.Tid) {
case Srch_crt_itm.Tid__word: bfr.Add(node.Raw); break;
case Srch_crt_itm.Tid__word_quote: bfr.Add_byte_quote().Add(node.Raw).Add_byte_quote(); break;
case Srch_crt_itm.Tid__and:
case Srch_crt_itm.Tid__or:
bfr.Add_byte(Byte_ascii.Paren_bgn);
Srch_crt_itm[] subs = node.Subs;
int subs_len = subs.length;
for (int i = 0; i < subs_len; ++i) {
if (i != 0)
bfr.Add_str_a7(node.Tid == Srch_crt_itm.Tid__and ? " AND " : " OR ");
subs[i].Accept_visitor(this);
}
bfr.Add_byte(Byte_ascii.Paren_end);
break;
case Srch_crt_itm.Tid__not:
bfr.Add_str_a7("NOT ");
node.Subs[0].Accept_visitor(this);
break;
case Srch_crt_itm.Tid__invalid: break; // should not happen
default: throw Err_.new_unhandled_default(node.Tid);
}
}
}

View File

@@ -0,0 +1,62 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.crts.visitors; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.searchers.crts.*;
public class Srch_crt_visitor__words implements Srch_crt_visitor {
private final List_adp words_list = List_adp_.new_();
public byte Words_tid() {return words_tid;} private byte words_tid;
public Srch_crt_itm Words_nth() {return words_nth;} private Srch_crt_itm words_nth;
public Srch_crt_itm[] Words_ary() {return (Srch_crt_itm[])words_list.To_ary_and_clear(Srch_crt_itm.class);}
public void Gather(Srch_crt_itm root) {
words_list.Clear();
words_tid = Srch_crt_mgr.Tid__ands;
words_nth = null;
Visit(root);
if (words_list.Count() == 1)
words_tid = Srch_crt_mgr.Tid__one;
}
public void Visit(Srch_crt_itm itm) {
int itm_tid = itm.Tid;
switch (itm_tid) {
case Srch_crt_itm.Tid__and:
case Srch_crt_itm.Tid__or:
if (itm_tid == Srch_crt_itm.Tid__or)
words_tid = Srch_crt_mgr.Tid__mixed;
Srch_crt_itm[] subs = itm.Subs;
int subs_len = subs.length;
for (int i = 0; i < subs_len; ++i)
Visit(subs[i]);
break;
case Srch_crt_itm.Tid__word:
case Srch_crt_itm.Tid__word_quote:
case Srch_crt_itm.Tid__not:
if ( itm_tid == Srch_crt_itm.Tid__not
&& itm.Subs.length == 1) {
Srch_crt_itm lone = itm.Subs[0];
if ( lone.Tid == Srch_crt_itm.Tid__word
|| lone.Tid == Srch_crt_itm.Tid__word_quote)
words_nth = lone;
}
else
words_nth = itm;
words_list.Add(itm);
break;
case Srch_crt_itm.Tid__invalid: break; // should not happen
default: throw Err_.new_unhandled_default(itm.Tid);
}
}
}

View File

@@ -0,0 +1,27 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.rslts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.core.primitives.*;
class Hash_adp__int {
private final Hash_adp hash = Hash_adp_.new_();
private final Int_obj_ref tmp_key = Int_obj_ref.neg1_();
public void Clear() {hash.Clear();}
public Object Get_by(int key) {return hash.Get_by(tmp_key.Val_(key));}
public void Add(int key, Object obj) {hash.Add(Int_obj_ref.new_(key), obj);}
public void Add_if_dupe_use_1st(int key, Object obj) {hash.Add_if_dupe_use_1st(Int_obj_ref.new_(key), obj);}
}

View File

@@ -0,0 +1,32 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.rslts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
public class Srch_rslt_cache {
private final Hash_adp_bry hash = Hash_adp_bry.cs();
public void Clear() {hash.Clear();}
public Srch_rslt_list Get_or_new(byte[] key) {
Srch_rslt_list rv = (Srch_rslt_list)hash.Get_by(key);
if (rv == null) {
rv = new Srch_rslt_list();
hash.Add(key, rv);
}
rv.Rslts_are_first = true;
rv.Rslts_are_enough = false;
return rv;
}
}

View File

@@ -0,0 +1,22 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.rslts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
public interface Srch_rslt_cbk {
void On_rslts_found(Srch_search_qry qry, Srch_rslt_list rslts_list, int rslts_bgn, int rslts_end);
void On_cancel();
}

View File

@@ -0,0 +1,25 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.rslts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
public class Srch_rslt_cbk_ {
public static final Srch_rslt_cbk Noop = new Srch_rslt_cbk__noop();
}
class Srch_rslt_cbk__noop implements Srch_rslt_cbk {
public void On_rslts_found(Srch_search_qry qry, Srch_rslt_list rslts_list, int rslts_bgn, int rslts_end) {}
public void On_cancel() {}
}

View File

@@ -0,0 +1,62 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.rslts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
public class Srch_rslt_list {
private final Ordered_hash key_hash = Ordered_hash_.New_bry();
private final Hash_adp__int id_hash = new Hash_adp__int();
public int Score_bgn = gplx.dbs.percentiles.Percentile_rng.Score_null;
public int Score_len = gplx.dbs.percentiles.Percentile_rng.Score_null;
public boolean Rslts_are_first;
public boolean Rslts_are_enough;
public boolean Rslts_are_done;
public int Len() {return key_hash.Len();}
public boolean Has(byte[] key) {return key_hash.Has(key);}
public Srch_rslt_row Get_by(byte[] key) {return (Srch_rslt_row)key_hash.Get_by(key);}
public Srch_rslt_row Get_at(int i) {return (Srch_rslt_row)key_hash.Get_at(i);}
public void Clear() {key_hash.Clear(); id_hash.Clear();}
public void Add(Srch_rslt_row row) {key_hash.Add(row.Key, row);}
public void Sort() {key_hash.Sort_by(Srch_rslt_row_sorter.Score_dsc);}
public boolean Ids__has(int id) {return (Srch_rslt_row)id_hash.Get_by(id) != null;}
public Srch_rslt_row Ids__get(int id) {return (Srch_rslt_row)id_hash.Get_by(id);}
public void Ids__add(int id, Srch_rslt_row r) {id_hash.Add(id, r);}
public void Merge(Srch_rslt_list list) {
list.Sort();
int list_len = list.Len();
for (int i = 0; i < list_len; ++i) {
Srch_rslt_row row = list.Get_at(i);
this.Add(row);
}
list.Clear();
}
public void Process_rdr_done(gplx.dbs.percentiles.Percentile_rng rng, boolean rslts_are_enough, boolean rslts_are_done) {
this.Score_bgn = rng.Score_bgn();
this.Score_len = rng.Score_len();
this.Rslts_are_enough = rslts_are_enough;
this.Rslts_are_done = rslts_are_done;
}
}
class Srch_rslt_row_sorter implements gplx.core.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Srch_rslt_row lhs = (Srch_rslt_row)lhsObj;
Srch_rslt_row rhs = (Srch_rslt_row)rhsObj;
int rv = -Int_.Compare(lhs.Page_score, rhs.Page_score);
if (rv != CompareAble_.Same) return rv;
return Bry_.Compare(lhs.Page_ttl.Page_txt(), rhs.Page_ttl.Page_txt());
}
public static final Srch_rslt_row_sorter Score_dsc = new Srch_rslt_row_sorter();
}

View File

@@ -0,0 +1,53 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.rslts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.xowa.wikis.data.tbls.*;
public class Srch_rslt_list_ {
public static boolean Add_if_new(Srch_search_ctx ctx, Srch_rslt_list rslts, Srch_rslt_row row) {
Srch_rslt_list_.Highlight(ctx, row); // always highlight title first; needed for suggest_box to update highlighting when increasing word; EX: Eart -> Earth; "Earth" should be highlighted, not "Eart"
return
( !rslts.Has(row.Key) // ignore: page already added by another word; EX: "A B"; word is "B", but "A B" already added by "A"
&& !rslts.Ids__has(row.Page_id) // ignore: page already added by page-tbl or by redirect
&& !Redirect_exists(rslts, row) // ignore: page is redirect, and target page already added
);
}
public static void Get_redirect_ttl(Xowd_page_tbl page_tbl, Xowd_page_itm tmp_page_itm, Srch_rslt_row row) {
int redirect_id = row.Page_redirect_id;
if (redirect_id == Srch_rslt_row.Page_redirect_id_null) return;
if (!page_tbl.Select_by_id(tmp_page_itm, redirect_id)) {Xoa_app_.Usr_dlg().Warn_many("", "", "page not found for redirect_id; redirect_id=~{0}", redirect_id); return;}
row.Page_redirect_ttl = Xoa_ttl.Replace_unders(tmp_page_itm.Ttl_page_db());
}
private static void Highlight(Srch_search_ctx ctx, Srch_rslt_row row) {
try {row.Page_ttl_highlight = ctx.Highlight_mgr.Highlight(row.Page_ttl.Full_txt_w_ttl_case());} // NOTE: always highlight row; needed for when search done in url_bar (highlight=n) and then same search reused for search (highlight=y)
catch (Exception e) {Xoa_app_.Usr_dlg().Warn_many("", "", "highlight failed; ttl=~{0} err=~{1}", row.Page_ttl_wo_ns, Err_.Message_gplx_log(e));}
}
private static boolean Redirect_exists(Srch_rslt_list rslts, Srch_rslt_row cur_row) {
int trg_id = cur_row.Page_redirect_id;
if (trg_id == Srch_rslt_row.Page_redirect_id_null) { // src_page is not redirect
return false;
} else { // src_page is redirect
Srch_rslt_row trg_row = rslts.Ids__get(trg_id);
if (trg_row == null) { // trg_page has not been seen before
rslts.Ids__add(trg_id, cur_row); // add trg_id to known ids; handles double-redirects; 1 -> 2 -> 3;
return false;
}
else // trg_page has been seen before
return true;
}
}
}

View File

@@ -0,0 +1,61 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.rslts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
public class Srch_rslt_row {
public Srch_rslt_row(byte[] key, byte[] wiki_bry, Xoa_ttl page_ttl, int page_ns, byte[] page_ttl_wo_ns, int page_id, int page_len, int page_score, int page_redirect_id) {
this.Key = key;
this.Wiki_bry = wiki_bry;
this.Page_id = page_id;
this.Page_ttl = page_ttl;
this.Page_ns = page_ns;
this.Page_ttl_wo_ns = page_ttl_wo_ns;
this.Page_len = page_len;
this.Page_redirect_id = page_redirect_id;
this.Page_score = page_score;
}
public final byte[] Key;
public final byte[] Wiki_bry;
public final int Page_id;
public final Xoa_ttl Page_ttl;
public final int Page_ns;
public final byte[] Page_ttl_wo_ns;
public final int Page_len;
public final int Page_redirect_id;
public final int Page_score;
public byte[] Page_redirect_ttl;
public byte[] Page_ttl_highlight;
public byte[] Page_ttl_display(boolean html) {
byte[] rv = html ? Page_ttl_highlight : Page_ttl.Full_txt_w_ttl_case();
if (Page_redirect_id == Page_redirect_id_null)
return rv;
else {
byte[] redirect_dlm = html ? Bry__redirect__html : Bry__redirect__text;
return Bry_.Add(rv, redirect_dlm, Page_redirect_ttl);
}
}
public static byte[] Bld_key(byte[] wiki_domain, int page_id) {return Bry_.Add(wiki_domain, Byte_ascii.Pipe_bry, Int_.To_bry(page_id));}
public static Srch_rslt_row New(byte[] wiki_bry, Xoa_ttl page_ttl, int page_id, int page_len, int page_score, int redirect_id) {
return new Srch_rslt_row(Bld_key(wiki_bry, page_id), wiki_bry, page_ttl, page_ttl.Ns().Id(), page_ttl.Page_db(), page_id, page_len, page_score, redirect_id);
}
public static final int Page_redirect_id_null = gplx.xowa.wikis.data.tbls.Xowd_page_itm.Redirect_id_null;
public static final String Str__redirect__text = " -> ";
private static final byte[]
Bry__redirect__html = Bry_.new_u8("") // 8592; 8594
, Bry__redirect__text = Bry_.new_a7(Str__redirect__text);
}

View File

@@ -0,0 +1,24 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.slabs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
public class Srch_slab_itm {
public Srch_slab_itm(byte[] wiki, int bgn, int end) {this.wiki = wiki; this.bgn = bgn; this.end = end;}
public byte[] Wiki() {return wiki;} private final byte[] wiki;
public int Bgn() {return bgn;} private final int bgn;
public int End() {return end;} private final int end;
}

View File

@@ -0,0 +1,34 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.slabs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.core.brys.*;
public class Srch_slab_itm_parser {
private final List_adp itm_list = List_adp_.new_();
private final Bry_rdr rdr = new Bry_rdr();
public Srch_slab_itm[] Parse(byte[] raw) { // EX: en.wikipedia.org|41|60;en.wiktionary.org|21|40;
rdr.Init_by_src(raw);
while (!rdr.Pos_is_eos()) {
byte[] wiki = rdr.Read_bry_to(Byte_ascii.Pipe);
int bgn = rdr.Read_int_to(Byte_ascii.Pipe);
int end = rdr.Read_int_to(Byte_ascii.Semic);
Srch_slab_itm itm = new Srch_slab_itm(wiki, bgn, end);
itm_list.Add(itm);
}
return (Srch_slab_itm[])itm_list.To_ary_and_clear(Srch_slab_itm.class);
}
}

View File

@@ -0,0 +1,163 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.wkrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.dbs.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.addons.searchs.dbs.*; import gplx.xowa.addons.searchs.searchers.crts.*; import gplx.xowa.addons.searchs.searchers.rslts.*; import gplx.dbs.percentiles.*;
import gplx.xowa.langs.cases.*; import gplx.xowa.addons.searchs.parsers.*;
public class Srch_link_wkr extends Percentile_select_base {
private final Srch_link_wkr_sql sql_mkr = new Srch_link_wkr_sql();
private final Db_attach_mgr attach_mgr = new Db_attach_mgr();
private final Srch_rslt_list tmp_rslts = new Srch_rslt_list();
private Srch_rslt_list rslts_list; private Srch_rslt_cbk rslt_cbk; private Srch_search_ctx ctx;
private Xowd_page_tbl page_tbl;
private Db_stmt stmt;
private int rslts_bgn, rslts_end;
private Srch_rslt_row cur_row; private final Xowd_page_itm tmp_page_itm = new Xowd_page_itm();
private int link_tbl_idx, link_tbl_nth; private boolean link_loop_done;
private Srch_crt_itm sql_root;
public void Search(Srch_rslt_list rslts_list, Srch_rslt_cbk rslt_cbk, Srch_search_ctx ctx) {
// init
super.cxl = ctx.Cxl;
super.rng = ctx.Score_rng;
super.rng_log = new Percentile_rng_log(ctx.Addon.Db_mgr().Cfg().Link_score_max());
rng_log.Init(ctx.Qry.Phrase.Orig, ctx.Rslts_needed);
this.rslts_list = rslts_list; this.rslt_cbk = rslt_cbk; this.ctx = ctx;
this.rslts_bgn = rslts_list.Len(); this.rslts_end = rslts_bgn;
this.page_tbl = ctx.Tbl__page;
try {
// enough results at start; occurs in Special:Search when revisiting slabs; EX: 1-100 -> 101-200 -> 1-100
if (ctx.Qry.Slab_end < rslts_list.Len()) {
rslts_list.Rslts_are_enough = true;
rslt_cbk.On_rslts_found(ctx.Qry, rslts_list, 0, rslts_list.Len());
return;
}
// prepare for iteration
this.link_tbl_idx = 0;
this.link_tbl_nth = ctx.Tbl__link__ary.length - 1;
sql_root = Srch_link_wkr_.Find_sql_root(ctx);
attach_mgr.Init(new Db_attach_itm("page_db", ctx.Db__core.Conn()), new Db_attach_itm("word_db", ctx.Tbl__word.conn));
super.Select();
}
finally {
try {
// gplx.core.consoles.Console_adp__sys.Instance.Write_str_w_nl("detaching: " + String_.new_u8(ctx.Qry.Phrase.Lcase_wild) + " " + Int_.To_str(ctx.Score_rng.Score_bgn()) + " " + Int_.To_str(ctx.Score_rng.Score_end()) + " " + attach_mgr.List__to_str());
attach_mgr.Detach();
stmt = Db_stmt_.Rls(stmt);
}
catch (Exception e) {
gplx.core.consoles.Console_adp__sys.Instance.Write_str_w_nl("detaching err: " + String_.new_u8(ctx.Qry.Phrase.Orig) + " " + Int_.To_str(ctx.Score_rng.Score_bgn()) + Err_.Message_lang(e));
}
}
}
@Override protected Db_rdr Rdr__init() {
try {
Db_conn link_tbl_conn = ctx.Tbl__link__ary[link_tbl_idx].conn;
attach_mgr.Main_conn_(link_tbl_conn);
sql_mkr.Init(ctx, attach_mgr, sql_root);
if (stmt == null) stmt = sql_mkr.Make(ctx, attach_mgr, link_tbl_conn);
sql_mkr.Fill(stmt);
return stmt.Exec_select__rls_manual();
} finally {sql_mkr.Clear();}
}
@Override protected boolean Found_enough() {return (rslts_list.Len() + tmp_rslts.Len()) >= ctx.Qry.Slab_end;}
@Override protected void Rng__update(int rdr_found) {
link_loop_done = false;
if (ctx.Qry.Ns_mgr.Ns_main_only()) {
link_loop_done = true;
}
else {
if (link_tbl_idx == link_tbl_nth) {
link_tbl_idx = 0;
link_loop_done = true;
}
else {
++link_tbl_idx;
}
// NOTE: must do detach_database and rls_stmt b/c link_tbl_conn changes
attach_mgr.Detach();
stmt = Db_stmt_.Rls(stmt);
}
if (link_loop_done)
rng.Update(rslts_end - rslts_bgn);
}
@Override protected void Rdr__done(boolean rslts_are_enough, boolean rslts_are_done) {
if (!link_loop_done) return;
int tmp_rslts_len = tmp_rslts.Len();
// get redirect ttl; note that main rdr should be closed
for (int i = 0; i < tmp_rslts_len; ++i) {
Srch_rslt_row row = tmp_rslts.Get_at(i);
int redirect_id = row.Page_redirect_id;
if (redirect_id != Srch_rslt_row.Page_redirect_id_null)
Srch_rslt_list_.Get_redirect_ttl(page_tbl, tmp_page_itm, row);
}
// merge to rslts_list; notify; cleanup;
if (tmp_rslts_len > 0) rslts_list.Merge(tmp_rslts);
rslts_list.Process_rdr_done(rng, rslts_are_enough, rslts_are_done);
rslt_cbk.On_rslts_found(ctx.Qry, rslts_list, rslts_bgn, rslts_end);
rslts_list.Rslts_are_first = false;
rslts_bgn = rslts_end;
// gplx.core.consoles.Console_adp__sys.Instance.Write_str(rng_log.To_str_and_clear());
}
@Override protected boolean Row__read(Db_rdr rdr) {
if (!rdr.Move_next()) return false;
byte[] wiki_bry = ctx.Wiki_domain;
int page_id = rdr.Read_int(page_tbl.Fld_page_id());
byte[] key = Srch_rslt_row.Bld_key(wiki_bry, page_id);
this.cur_row = ctx.Cache__page.Get_by(key); // note that page could have been added from another word
if (cur_row == null) {
int page_len = rdr.Read_int(page_tbl.Fld_page_len());
int page_score = page_tbl.Fld_page_score() == Dbmeta_fld_itm.Key_null ? page_len : rdr.Read_int(page_tbl.Fld_page_score());
int page_ns_id = rdr.Read_int(page_tbl.Fld_page_ns());
byte[] page_ttl_wo_ns = rdr.Read_bry_by_str(page_tbl.Fld_page_title());
Xoa_ttl page_ttl = ctx.Wiki.Ttl_parse(page_ns_id, page_ttl_wo_ns);
this.cur_row = new Srch_rslt_row(key, wiki_bry, page_ttl, page_ns_id, page_ttl_wo_ns, page_id, page_len, page_score, rdr.Read_int(page_tbl.Fld_redirect_id()));
ctx.Cache__page.Add(cur_row);
}
return true;
}
@Override protected boolean Row__eval() {
if ( !ctx.Qry.Ns_mgr.Has(cur_row.Page_ns) // ignore: ns doesn't match
|| !Srch_link_wkr_.Matches(ctx.Crt_mgr__root, ctx.Addon.Ttl_parser(), ctx.Case_mgr, cur_row.Page_ttl_wo_ns) // ignore: ttl doesn't match ttl_matcher; EX: "A B"
)
return false;
boolean rv = Srch_rslt_list_.Add_if_new(ctx, rslts_list, cur_row);
if (rv) {
++rslts_end;
rslts_list.Ids__add(cur_row.Page_id, cur_row);
tmp_rslts.Add(cur_row);
}
return rv;
}
public static int Percentile_rng__calc_adj(int last_word_len) {
switch (last_word_len) {
case 1: return 0;
case 2: return 10;
case 3: return 20;
case 4: return 30;
case 5: return 40;
case 6: return 50;
case 7: return 60;
case 8: return 70;
default: return 80;
}
}
}

View File

@@ -0,0 +1,141 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.wkrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.xowa.addons.searchs.parsers.*; import gplx.xowa.langs.cases.*;
import gplx.xowa.addons.searchs.dbs.*; import gplx.xowa.addons.searchs.searchers.crts.*;
class Srch_link_wkr_ {
private static final Srch_word_count_wkr word_count_wkr = new Srch_word_count_wkr();
public static Srch_crt_itm Find_sql_root(Srch_search_ctx ctx) {
Srch_crt_mgr crt_mgr = ctx.Crt_mgr;
// lookup word_ids; needed for one, mixed, and ands
Srch_crt_itm[] words_ary = crt_mgr.Words_ary;
int words_len = words_ary.length;
for (int i = 0; i < words_len; ++i) {
Srch_crt_itm word = words_ary[i];
switch (word.Tid) {
case Srch_crt_itm.Tid__word:
if (word.Sql_data.Tid == Srch_crt_sql.Tid__eq) // look up word_id
word.Sql_data.Eq_id = ctx.Tbl__word.Select_or_empty(word.Raw).Id;
break;
case Srch_crt_itm.Tid__word_quote:
Srch_word_row[] rows = Find_sql_root__quoted(ctx, word.Raw);
if (rows != null && rows.length > 0) // override eq_id
word.Sql_data.Eq_id = rows[0].Id;
break;
}
}
if (crt_mgr.Words_tid != Srch_crt_mgr.Tid__ands) return ctx.Crt_mgr__root; // one and mixed returns root;
// ands need to do more db_lookup for rng words and identify the sql_root
Srch_crt_itm rv = null;
Srch_word_tbl word_tbl = ctx.Tbl__word;
int count_min = Int_.Max_value;
for (int i = 0; i < words_len; ++i) {
Srch_crt_itm sub = words_ary[i];
int sub_count = Find_sql_root__ands(ctx, word_tbl, sub);
if (sub_count < count_min) {
count_min = sub_count;
rv = sub;
}
}
return rv;
}
private static Srch_word_row[] Find_sql_root__quoted(Srch_search_ctx ctx, byte[] raw) {
List_adp tmp_list = List_adp_.new_();
byte[][] ary = Bry_split_.Split(raw, Byte_ascii.Space, Bool_.Y); // TODO: splitting by space is simplistic; should call Srch2_split_words
int words_len = ary.length;
for (int i = 0; i < words_len; ++i) {
byte[] word = ary[i];
Srch_word_row word_row = ctx.Tbl__word.Select_or_empty(word); if (word_row == Srch_word_row.Empty) continue;
tmp_list.Add(word_row);
}
if (tmp_list.Count() == 0) return null; // no words exist in db; EX: "xyz1 xyz2"
tmp_list.Sort_by(Srch_word_row_sorter__link_count.Desc);
Srch_word_row[] rows = (Srch_word_row[])tmp_list.To_ary_and_clear(Srch_word_row.class);
return rows;
}
private static int Find_sql_root__ands(Srch_search_ctx ctx, Srch_word_tbl word_tbl, Srch_crt_itm sub) {
if (sub.Tid == Srch_crt_itm.Tid__not) return Int_.Max_value;
int cached_count = ctx.Cache__word_counts.Get_as_int_or(sub.Raw, Int_.Min_value);
if (cached_count != Int_.Min_value) return cached_count;
int rv = Int_.Max_value;
if (sub.Sql_data.Tid == Srch_crt_sql.Tid__eq) {
Srch_word_row word = word_tbl.Select_or_empty(sub.Raw);
if (word != Srch_word_row.Empty) rv = word.Link_count;
}
else {
rv = word_count_wkr.Get_top_10(ctx, word_tbl, sub);
}
ctx.Cache__word_counts.Add_bry_int(sub.Raw, rv);
return rv;
}
public static boolean Matches(Srch_crt_itm node, Srch_text_parser text_parser, Xol_case_mgr case_mgr, byte[] ttl) {
byte[] ttl_lower = case_mgr.Case_build_lower(Xoa_ttl.Replace_unders(ttl));
byte[][] ttl_words = text_parser.Parse_to_bry_ary(Bool_.Y, ttl);
return Matches(node, ttl_lower, ttl_words);
}
private static boolean Matches(Srch_crt_itm node, byte[] ttl_lower, byte[][] ttl_words) {
int tid = node.Tid;
byte[] raw = node.Raw;
Srch_crt_itm[] subs = node.Subs;
int subs_len = subs.length;
switch (tid) {
case Srch_crt_itm.Tid__word: {
int len = ttl_words.length;
for (int i = 0; i < len; ++i) {
byte[] word = ttl_words[i];
if (node.Sql_data.Pattern == null) {
if (Bry_.Eq(word, raw)) return true;
}
else {
if (node.Sql_data.Pattern.Match(word)) return true;
}
}
return false;
}
case Srch_crt_itm.Tid__word_quote: return Bry_find_.Find_fwd(ttl_lower, raw) != Bry_find_.Not_found;// note that raw does not have quotes; EX: "B*" -> B*
case Srch_crt_itm.Tid__not: return !Matches(subs[0], ttl_lower, ttl_words);
case Srch_crt_itm.Tid__or: {
for (int i = 0; i < subs_len; ++i) {
Srch_crt_itm sub = subs[i];
if (Matches(sub, ttl_lower, ttl_words))
return true;
}
return false;
}
case Srch_crt_itm.Tid__and:
for (int i = 0; i < subs_len; ++i) {
Srch_crt_itm sub = subs[i];
if (!Matches(sub, ttl_lower, ttl_words))
return false;
}
return true;
case Srch_crt_itm.Tid__invalid: return false;
default: throw Err_.new_unhandled(tid);
}
}
}
class Srch_word_row_sorter__link_count implements gplx.core.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Srch_word_row lhs = (Srch_word_row)lhsObj;
Srch_word_row rhs = (Srch_word_row)rhsObj;
return -Int_.Compare(lhs.Link_count, rhs.Link_count);
}
public static final Srch_word_row_sorter__link_count Desc = new Srch_word_row_sorter__link_count(); Srch_word_row_sorter__link_count() {}
}

View File

@@ -0,0 +1,157 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.wkrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.dbs.*; import gplx.dbs.stmts.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.addons.searchs.searchers.crts.*; import gplx.xowa.addons.searchs.dbs.*; import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_link_wkr_sql {
private final Db_stmt_mgr stmt_mgr = new Db_stmt_mgr();
public void Clear() {stmt_mgr.Clear();}
public String Dbg(Srch_search_ctx ctx, Db_attach_mgr attach_mgr, Srch_crt_itm sql_root) {
stmt_mgr.Mode_is_stmt_(Bool_.N);
Init(ctx, attach_mgr, sql_root);
stmt_mgr.Mode_is_stmt_(Bool_.Y);
String rv = Write(ctx, attach_mgr);
stmt_mgr.Clear();
return rv;
}
public void Init(Srch_search_ctx ctx, Db_attach_mgr attach_mgr, Srch_crt_itm sql_root) {
synchronized (Fmt__link) { // THREAD:must synchronized on static Object, else 2 wikis with simultaneous search commands will write to same fmtr
stmt_mgr.Bfr().Add(Bry__page__bgn);
Bld_where(ctx, sql_root);
stmt_mgr.Bfr().Add(Bry__page__end);
}
}
public String Write(Srch_search_ctx ctx, Db_attach_mgr attach_mgr) {
String sql = stmt_mgr.Bfr().To_str_and_clear();
try {
// gplx.core.consoles.Console_adp__sys.Instance.Write_str_w_nl("attaching: " + String_.new_u8(ctx.Qry.Phrase.Lcase_wild) + " " + Int_.To_str(ctx.Score_rng.Score_bgn()) + " " + Int_.To_str(ctx.Score_rng.Score_end()) + " " + attach_mgr.List__to_str());
sql = attach_mgr.Resolve_sql(sql);
}
catch (Exception e) {
gplx.core.consoles.Console_adp__sys.Instance.Write_str_w_nl("attaching err: " + String_.new_u8(ctx.Qry.Phrase.Orig) + " " + Int_.To_str(ctx.Score_rng.Score_bgn()) + " " + Int_.To_str(ctx.Score_rng.Score_end()) + Err_.Message_lang(e));
}
return sql;
}
public Db_stmt Make(Srch_search_ctx ctx, Db_attach_mgr attach_mgr, Db_conn cur_link_conn) {
String sql = Write(ctx, attach_mgr);
attach_mgr.Attach();
return cur_link_conn.Stmt_sql(sql);
}
public void Fill(Db_stmt stmt) {
// gplx.core.consoles.Console_adp__sys.Instance.Write_str_w_nl(String_.new_u8(ctx.Qry.Phrase.Orig) + " " + Int_.To_str(ctx.Score_rng.Score_bgn()) + " " + Int_.To_str(ctx.Score_rng.Score_end()));
stmt_mgr.Fill_stmt_and_clear(stmt);
}
private void Bld_where(Srch_search_ctx ctx, Srch_crt_itm node) {
switch (node.Tid) {
case Srch_crt_itm.Tid__word:
case Srch_crt_itm.Tid__word_quote: // NOTE: quoted word is treated as Eq, except Eq_id is set to "lowest" word_id
Bld_leaf(ctx, node);
break;
case Srch_crt_itm.Tid__or:
case Srch_crt_itm.Tid__and:
Srch_crt_itm[] subs = node.Subs;
int subs_len = subs.length;
for (int i = 0; i < subs_len; ++i) {
Srch_crt_itm sub = subs[i];
if (sub.Tid == Srch_crt_itm.Tid__not) continue; // do not build sql for NOT itms; EX: a + (b, c) + -d
if (i != 0)
stmt_mgr.Bfr().Add_str_a7(node.Tid == Srch_crt_itm.Tid__and ? "INTERSECT\n" : "UNION\n");
Bld_where(ctx, sub);
}
break;
case Srch_crt_itm.Tid__not: break; // never check database for NOT node
case Srch_crt_itm.Tid__invalid: break; // should not happen
default: throw Err_.new_unhandled_default(node.Tid);
}
}
private void Bld_leaf(Srch_search_ctx ctx, Srch_crt_itm node) {
int node_idx = node.Idx;
int node_sql_tid = node.Sql_data.Tid;
int score_bgn = ctx.Score_rng.Score_bgn();
int score_end = ctx.Score_rng.Score_end();
Srch_word_tbl word_tbl = ctx.Tbl__word;
stmt_mgr.Bfr().Add(Bry__link__bgn);
switch (node_sql_tid) {
case Srch_crt_sql.Tid__eq: // EX: "earth"
stmt_mgr.Add_crt_int(word_tbl.fld_id, node.Sql_data.Eq_id);
stmt_mgr.Write_fmt(Fmt__word_id);
break;
case Srch_crt_sql.Tid__rng: // EX: "earth*"
stmt_mgr.Add_var_many(node_idx, "AND ", "search_word__word_text__link_score_max__link_score_min");
stmt_mgr.Add_crt_str(word_tbl.fld_text, node.Sql_data.Rng_bgn);
stmt_mgr.Add_crt_str(word_tbl.fld_text, node.Sql_data.Rng_end);
stmt_mgr.Add_crt_int(word_tbl.fld_link_score_max, score_bgn);
stmt_mgr.Add_crt_int(word_tbl.fld_link_score_min, score_end);
stmt_mgr.Write_fmt(Fmt__word_text__rng);
break;
case Srch_crt_sql.Tid__like: // EX: "*earth"
stmt_mgr.Add_var_many(node_idx, "WHERE ", "search_word__link_score_max__link_score_min");
stmt_mgr.Add_crt_int(word_tbl.fld_link_score_max, score_bgn);
stmt_mgr.Add_crt_int(word_tbl.fld_link_score_min, score_end);
stmt_mgr.Add_crt_str(word_tbl.fld_text, node.Sql_data.Like);
stmt_mgr.Write_fmt(Fmt__word_text__like);
break;
}
Srch_link_tbl link_tbl = ctx.Tbl__link__ary[0];
stmt_mgr.Add_crt_int(link_tbl.fld_link_score, score_bgn);
stmt_mgr.Add_crt_int(link_tbl.fld_link_score, score_end);
stmt_mgr.Write_fmt(Fmt__link);
}
private static final byte[]
Bry__page__bgn = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "SELECT p.page_id, p.page_namespace, p.page_title, p.page_len, p.page_score, p.page_redirect_id"
, "FROM <page_db>page p"
, "WHERE p.page_id IN"
, "("
, ""
))
, Bry__page__end = Bry_.new_a7(")\n")
, Bry__link__bgn = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "SELECT l.page_id"
, "FROM search_link l INDEXED BY search_link__word_id__link_score"
, "WHERE "
))
;
private static final String
Str__link__end = String_.Concat_lines_nl_skip_last
( "AND l.link_score >= ~{score_bgn}"
, "AND l.link_score < ~{score_end}"
, ""
)
, Str__word__text__bgn = String_.Concat_lines_nl_skip_last
( "l.word_id IN"
, "("
, "SELECT w~{uid}.word_id"
, "FROM <word_db>search_word w~{uid} INDEXED BY ~{index}"
, ""
)
, Str__word__text__rng = "WHERE w~{uid}.word_text >= ~{word_bgn} AND w~{uid}.word_text < ~{word_end}\n"
, Str__word__text__like = "AND w~{uid}.word_text LIKE ~{word_like} ESCAPE '|'\n"
, Str__word__text__mnx = String_.Concat_lines_nl_skip_last
( "~{and} w~{uid}.link_score_max >= ~{score_bgn}"
, "AND w~{uid}.link_score_min < ~{score_end}"
, ""
);
private static final Bry_fmt
Fmt__link = Bry_fmt.Auto(Str__link__end)
, Fmt__word_id = Bry_fmt.Auto("l.word_id = ~{word_uid}\n")
, Fmt__word_text__rng = Bry_fmt.New(Str__word__text__bgn + Str__word__text__rng + Str__word__text__mnx + ")\n", "uid", "and", "index", "word_bgn", "word_end", "score_bgn", "score_end")
, Fmt__word_text__like = Bry_fmt.New(Str__word__text__bgn + Str__word__text__mnx + Str__word__text__like + ")\n", "uid", "and", "index", "score_bgn", "score_end", "word_like")
;
public static final byte Like_escape_byte = Byte_ascii.Pipe;
}

View File

@@ -0,0 +1,39 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.wkrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import org.junit.*; import gplx.xowa.addons.searchs.parsers.*; import gplx.xowa.addons.searchs.searchers.crts.*; import gplx.xowa.addons.searchs.searchers.crts.visitors.*;
public class Srch_link_wkr_sql_tst {
private final Srch_link_wkr_sql_fxt fxt = new Srch_link_wkr_sql_fxt();
@Test public void Rng() {
fxt.Run__search("a").Test__eq
( "select"
);
}
}
class Srch_link_wkr_sql_fxt {
private final Srch_link_wkr_sql link_wkr = new Srch_link_wkr_sql();
public Srch_link_wkr_sql_fxt Run__search(String search) {
// attach_mgr.Init(cur_link_tbl.conn, new Db_attach_itm("page_db", ctx.Db__core.Conn()), new Db_attach_itm("word_db", ctx.Tbl__word.conn));
// link_wkr.Init(ctx, attach_mgr);
// this.actl_sql = link_wkr.Write(ctx, attach_mgr);
link_wkr.Clear();
return this;
}
public void Test__eq(String... v) {
}
}

View File

@@ -0,0 +1,72 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.wkrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.addons.searchs.searchers.rslts.*;
import gplx.xowa.addons.searchs.searchers.crts.*;
public class Srch_page_tbl_wkr {
private final Xowd_page_itm tmp_page_row = new Xowd_page_itm();
private final Bry_bfr tmp_bfr = Bry_bfr.new_();
public void Search(Srch_search_ctx ctx, Srch_rslt_cbk cbk) {
byte[] search_raw = To_bry_or_null(tmp_bfr, ctx.Scanner_syms.Wild(), ctx.Crt_mgr); // build up search String but handle escapes "\+" -> "+"
if (search_raw == null) return; // search-term has not or symbols; EX: "earth -history"; "(earth & history)"
Xoa_ttl ttl = ctx.Wiki.Ttl_parse(search_raw); if (ttl == null) return;
Xowd_page_tbl page_tbl = ctx.Tbl__page;
if (ctx.Cxl.Canceled()) return;
if (page_tbl.Select_by_ttl(tmp_page_row, ttl.Ns(), ttl.Page_db())) {
if (ctx.Cxl.Canceled()) return;
Srch_rslt_row row = Srch_rslt_row.New(ctx.Wiki_domain, ttl, tmp_page_row.Id(), tmp_page_row.Text_len(), ctx.Addon.Db_mgr().Cfg().Link_score_max() * 3, tmp_page_row.Redirect_id());
if (Srch_rslt_list_.Add_if_new(ctx, ctx.Rslts_list, row)) {
Srch_rslt_list_.Get_redirect_ttl(page_tbl, tmp_page_row, row);
ctx.Rslts_list.Add(row);
ctx.Rslts_list.Ids__add(row.Page_id, row);
cbk.On_rslts_found(ctx.Qry, ctx.Rslts_list, 0, 1);
ctx.Rslts_list.Rslts_are_first = false;
}
}
}
public static byte[] To_bry_or_null(Bry_bfr bfr, byte wildcard_byte, Srch_crt_mgr mgr) {
if (mgr.Words_tid == Srch_crt_mgr.Tid__mixed) return null;
Srch_crt_tkn[] tkns = mgr.Tkns;
int len = tkns.length;
for (int i = 0; i < len; ++i) {
Srch_crt_tkn tkn = tkns[i];
switch (tkn.Tid) {
case Srch_crt_tkn.Tid__word:
case Srch_crt_tkn.Tid__word_w_quote:
break;
default:
return null;
}
if (i != 0) bfr.Add_byte_space();
byte[] tkn_raw = tkn.Val;
int tkn_raw_len = tkn_raw.length;
int wildcard_pos = Bry_find_.Find_fwd(tkn_raw, wildcard_byte, 0, tkn_raw_len);
if (wildcard_pos != Bry_find_.Not_found) {
int last_pos = tkn_raw_len - 1;
if (wildcard_pos == last_pos)
bfr.Add_mid(tkn_raw, 0, last_pos);
else
return null;
}
else
bfr.Add(tkn.Val);
}
return bfr.To_bry_and_clear();
}
}

View File

@@ -0,0 +1,47 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.wkrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import org.junit.*; import gplx.xowa.addons.searchs.parsers.*; import gplx.xowa.addons.searchs.searchers.crts.*; import gplx.xowa.addons.searchs.searchers.crts.visitors.*;
public class Srch_page_tbl_wkr_tst {
private final Srch_page_tbl_wkr_fxt fxt = new Srch_page_tbl_wkr_fxt();
@Test public void Word__one() {fxt.Test__to_bry_or_null("a" , "a");}
@Test public void Word__many() {fxt.Test__to_bry_or_null("a b c" , "a b c");}
@Test public void Wild__end() {fxt.Test__to_bry_or_null("a*" , "a");}
@Test public void Wild__both() {fxt.Test__to_bry_or_null("a*b*" , null);}
@Test public void Quote() {fxt.Test__to_bry_or_null("\"a b\"" , "a b");}
@Test public void Quote__mixed() {fxt.Test__to_bry_or_null("a \"b \"\" c\" d" , "a b \" c d");}
@Test public void Escape() {fxt.Test__to_bry_or_null("a\\+" , "a+");}
@Test public void Not() {fxt.Test__to_bry_or_null("a -b" , null);}
@Test public void And() {fxt.Test__to_bry_or_null("a + b" , null);}
@Test public void Or() {fxt.Test__to_bry_or_null("a , b" , null);}
@Test public void Parens() {fxt.Test__to_bry_or_null("(a)" , null);}
}
class Srch_page_tbl_wkr_fxt {
private final Srch_crt_parser crt_parser;
private final Bry_bfr tmp_bfr = Bry_bfr.new_();
public Srch_page_tbl_wkr_fxt() {
crt_parser = new Srch_crt_parser(Srch_crt_scanner_syms.Dflt);
Srch_text_parser text_parser = new Srch_text_parser();
text_parser.Init_for_ttl(gplx.xowa.langs.cases.Xol_case_mgr_.A7());
}
public void Test__to_bry_or_null(String src_str, String expd) {
byte[] src_bry = Bry_.new_a7(src_str);
Srch_crt_mgr crt_mgr = crt_parser.Parse_or_invalid(src_bry, Bool_.N);
Tfds.Eq(expd, String_.new_u8(Srch_page_tbl_wkr.To_bry_or_null(tmp_bfr, Srch_search_addon.Wildcard__star, crt_mgr)));
}
}

View File

@@ -0,0 +1,78 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.searchers.wkrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.searchers.*;
import gplx.dbs.*; import gplx.dbs.stmts.*; import gplx.dbs.percentiles.*;
import gplx.xowa.addons.searchs.dbs.*; import gplx.xowa.addons.searchs.searchers.crts.*;
class Srch_word_count_wkr extends Percentile_select_base {
private Srch_word_tbl word_tbl; private Srch_db_cfg db_cfg;
private Srch_crt_itm sub;
private int total_link_count, rows_read; private boolean score_too_low;
private final Db_stmt_mgr stmt_mgr = new Db_stmt_mgr(); private Db_stmt stmt;
public int Get_top_10(Srch_search_ctx ctx, Srch_word_tbl word_tbl, Srch_crt_itm sub) {
super.cxl = ctx.Cxl;
this.db_cfg = ctx.Addon.Db_mgr().Cfg();
super.rng = new Percentile_rng().Init(db_cfg.Word_count(), db_cfg.Link_count_score_max());
super.rng.Select_init(10, Percentile_rng.Score_null, Percentile_rng.Score_null, 0);
super.rng_log = new Percentile_rng_log(db_cfg.Link_count_score_max());
rng_log.Init(sub.Raw, 10);
this.word_tbl = word_tbl;
this.sub = sub;
this.total_link_count = 0;
this.rows_read = 0;
this.score_too_low = false;
try {this.Select();}
finally {stmt = Db_stmt_.Rls(stmt);}
if (score_too_low) return Srch_db_cfg_.Link_count_score_cutoff;
else if (rows_read == 1) return total_link_count * 2;
else return total_link_count;
}
@Override protected Db_rdr Rdr__init() {
stmt_mgr.Add_crt_int(word_tbl.fld_link_count_score, rng.Score_bgn());
stmt_mgr.Add_crt_int(word_tbl.fld_link_count_score, rng.Score_end());
stmt_mgr.Add_crt_str(word_tbl.fld_text, sub.Sql_data.Rng_bgn);
stmt_mgr.Add_crt_str(word_tbl.fld_text, sub.Sql_data.Rng_end);
if (stmt == null) stmt = stmt_mgr.Make_stmt(word_tbl.conn, Fmt__main);
stmt_mgr.Fill_stmt_and_clear(stmt);
return stmt.Exec_select__rls_manual();
}
@Override protected boolean Row__read(Db_rdr rdr) {
if (!rdr.Move_next()) return false;
int cur_link_count = rdr.Read_int(word_tbl.fld_link_count);
total_link_count += cur_link_count;
++rows_read;
return true;
}
@Override protected boolean Found_enough() {
if (rng.Score_bgn() <= db_cfg.Link_count_score_cutoff()) score_too_low = true;
return rows_read > 0 || score_too_low;
}
@Override protected void Rdr__done(boolean rslts_are_enough, boolean rslts_are_done) {
// if (rslts_are_enough) gplx.core.consoles.Console_adp__sys.Instance.Write_str(rng_log.To_str_and_clear());
}
private static Bry_fmt
Fmt__main = Bry_fmt.Auto(String_.Concat_lines_nl_skip_last
( "SELECT w.link_count"
, "FROM search_word w INDEXED BY search_word__link_count_score__word_text"
, "WHERE w.link_count_score >= ~{score_min}"
, "AND w.link_count_score < ~{score_max}"
, "AND w.word_text >= ~{rng_bgn}"
, "AND w.word_text < ~{rng_end}"
, "LIMIT 1"
));
}

View File

@@ -0,0 +1,68 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.specials; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.core.net.*;
import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_qarg_mgr {
public Srch_qarg_mgr(Srch_ns_mgr ns_mgr) {this.ns_mgr = ns_mgr;}
public Srch_ns_mgr Ns_mgr() {return ns_mgr;} private final Srch_ns_mgr ns_mgr;
public byte[] Search_raw() {return search_raw;} private byte[] search_raw; public Srch_qarg_mgr Search_raw_(byte[] v) {search_raw = v; return this;}
public int Slab_idx() {return slab_idx;} private int slab_idx;
public byte[] Cancel() {return cancel;} private byte[] cancel;
public boolean Simple_search() {return simple_search;} private boolean simple_search;
public Srch_qarg_mgr Clear() {
ns_mgr.Clear();
this.search_raw = null;
this.slab_idx = 0;
this.cancel = null;
this.simple_search = false;
return this;
}
public void Parse(Gfo_qarg_itm[] qargs_ary) {
if (qargs_ary == null) return;
int len = qargs_ary.length;
for (int i = 0; i < len; ++i) {
Gfo_qarg_itm qarg = qargs_ary[i];
byte[] key = qarg.Key_bry();
byte tid = qarg_regy.Get_as_byte_or(key, Byte_.Max_value_127);
if (tid == Byte_.Max_value_127) { // unknown qarg; check for ns*; EX: &ns0=1&ns8=1; NOTE: lowercase only
if (Bry_.Has_at_bgn(key, Ns_bry))
ns_mgr.Add_by_parse(key, qarg.Val_bry());
}
else {
switch (tid) {
case Uid__search: this.search_raw = Bry_.Replace(qarg.Val_bry(), Byte_ascii.Plus, Byte_ascii.Space); break;
case Uid__slab_idx: this.slab_idx = Bry_.To_int_or(qarg.Val_bry(), 0); break;
case Uid__cancel: this.cancel = qarg.Val_bry(); break;
case Uid__simple_search: this.simple_search = Bry_.Eq(qarg.Val_bry(), Bool_.Y_bry); break;
default: break;
}
}
}
ns_mgr.Add_main_if_empty();
}
private static byte[] Ns_bry = Bry_.new_a7("ns");
private static final byte Uid__search = 0, Uid__slab_idx = 1, Uid__cancel = 2, Uid__simple_search = 3;
public static final byte[] Bry__slab_idx = Bry_.new_a7("xowa_page_index"), Bry__cancel = Bry_.new_a7("cancel");
private static final Hash_adp_bry qarg_regy = Hash_adp_bry.ci_a7()
.Add_str_byte("search" , Uid__search)
.Add_bry_byte(Bry__slab_idx , Uid__slab_idx)
.Add_bry_byte(Bry__cancel , Uid__cancel)
.Add_str_byte("simple_search" , Uid__simple_search)
;
}

View File

@@ -0,0 +1,105 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.specials; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.core.threads.*;
import gplx.xowa.files.gui.*; import gplx.xowa.guis.views.*;
import gplx.xowa.addons.searchs.specials.htmls.*; import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_special_cmd implements GfoInvkAble, Srch_rslt_cbk, Xog_tab_close_lnr {
private final Srch_special_searcher mgr; private final Srch_search_qry qry;
public final Xow_wiki wiki; private final Xog_tab_close_mgr tab_close_mgr; private final Xog_js_wkr js_wkr;
private Srch_html_row_wkr html_row_wkr; private final boolean async;
public final byte[] key; private boolean canceled = false;
public Srch_special_cmd(Srch_special_searcher mgr, Srch_search_qry qry, Xow_wiki wiki, Xog_tab_close_mgr tab_close_mgr, Xog_js_wkr js_wkr, byte[] key, boolean search_is_async) {
this.mgr = mgr; this.qry = qry; this.wiki = wiki; this.tab_close_mgr = tab_close_mgr; this.js_wkr = js_wkr; this.key = key;
this.async = wiki.App().Mode().Tid_is_gui() && search_is_async;
}
public void On_cancel() {
canceled = true;
Xoa_app_.Usr_dlg().Prog_many("", "", "search canceled: key=~{0}", key);
this.Hide_cancel_btn();
}
public void Search() {
if (async) { // NOTE: async useful with multiple wikis; allows parallel searches;
Srch_html_row_bldr html_row_bldr = new Srch_html_row_bldr(new gplx.xowa.htmls.core.htmls.utls.Xoh_lnki_bldr(wiki.App(), wiki.App().Html__href_wtr()));
html_row_wkr = new Srch_html_row_wkr(html_row_bldr, js_wkr, qry.Slab_end - qry.Slab_bgn, wiki.Domain_bry());
Thread_adp_.invk_(gplx.xowa.apps.Xoa_thread_.Key_special_search_db, this, Invk_search_db).Start();
}
else
Search_db();
}
private void Search_db() {
synchronized (mgr) { // THREAD: needed else multiple Special:Search pages will fail at startup; DATE:2016-03-27
tab_close_mgr.Add(this);
// DEPRECATE: causes search to fail when using go back / go forward; DELETE:2016-05; DATE:2016-03-27
// if (async) {
// while (!page.Html_data().Mode_wtxt_shown()) // NOTE:must check to see if page is shown; else async can happen first, and then be overwritten by page_showing; DATE:2015-04-26
// Thread_adp_.Sleep(100);
// }
Srch_search_addon.Get(wiki).Search(qry, this);
mgr.Search__done(this);
if (canceled) return; // NOTE: must check else throws SWT exception
this.Hide_cancel_btn();
}
Xoa_app_.Usr_dlg().Prog_many("", "", "");
}
private void Hide_cancel_btn() {Thread_adp_.invk_(gplx.xowa.apps.Xoa_thread_.Key_special_search_cancel, this, Invk_hide_cancel).Start();}
private void Hide_cancel_btn_async() {js_wkr.Html_atr_set("xowa_cancel_" + wiki.Domain_str(), "style", "display:none;");}
public void On_rslts_found(Srch_search_qry qry, Srch_rslt_list rslts_list, int rslts_bgn, int rslts_end) {
if (rslts_list.Rslts_are_first) {
if (rslts_bgn > qry.Slab_bgn) {
for (int i = qry.Slab_bgn; i < rslts_bgn; ++i) {
Srch_rslt_row row = rslts_list.Get_at(i);
html_row_wkr.On_rslt_found(row);
}
}
}
for (int i = rslts_bgn; i < rslts_end; ++i) {
if (i < qry.Slab_bgn) continue; // do not write row if < slab_bgn; occurs when restarting app directly at page > 1; EX: 11-20 requested; 1-20 returned; do not write 1-10;
if (i >= qry.Slab_end) break; // do not write row if > slab_end; occurs when paging forward; EX: 01-10 requested; 1-12 retrieved; do not write 11, 12
Srch_rslt_row row = rslts_list.Get_at(i);
html_row_wkr.On_rslt_found(row);
}
}
public boolean When_close(Xog_tab_itm tab, Xoa_url url) {
if (url != Xoa_url.Null) { // not called by close_tab (Ctrl+W)
byte[] cancel_arg = url.Qargs_mgr().Get_val_bry_or(Srch_qarg_mgr.Bry__cancel, null);
if (cancel_arg != null) return true; // cancel arg exists; assume tab is not being closed; note that cancel will be processed by Xows_page__special; DATE:2015-04-30
}
this.On_cancel();
return true;
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_search_db)) Search_db();
else if (ctx.Match(k, Invk_hide_cancel)) Hide_cancel_btn_async();
else return GfoInvkAble_.Rv_unhandled;
return this;
}
private static final String Invk_search_db = "search_db", Invk_hide_cancel = "hide_cancel";
}
/*
NOTE:show_existing. code needed to show A1
EX: search="A*": "A" has 400 words; "A1" has 1;
. search 1-20 returns 20 words for A and 1 word for A1.
.. the 1st A word has a len of 999 and the 20th A word has a length of 900;
.. A1 has a length of 799
. search 21-40 returns 20 words for A
.. the 21st word has a len of 899 and the 40th has a len of 800
.. A1 should show up briefly, and then get pushed off screen by 21-40
. search 61-40 returns 20 words for A
.. A1 must show up
*/

View File

@@ -15,23 +15,77 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
package gplx.xowa.addons.searchs.specials; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.core.primitives.*; import gplx.xowa.apps.apis.xowa.specials.*;
import gplx.xowa.wikis.domains.*; import gplx.xowa.wikis.domains.crts.*;
public class Xows_page__search implements Xows_page, GfoInvkAble, GfoEvObj {
private final Xoae_app app; private final Xow_domain_itm wiki_domain; private final Xoapi_search search_api;
private final Xows_core search_mgr; private final Xows_arg_mgr args_mgr = new Xows_arg_mgr();
import gplx.xowa.wikis.domains.*; import gplx.xowa.wikis.domains.crts.*;
import gplx.xowa.specials.*; import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.searchers.cbks.*;
public class Srch_special_page implements Xows_page, GfoInvkAble, GfoEvObj {
private final Xoae_app app; private final Xow_domain_itm wiki_domain; private final Xoapi_search search_api;
private final Srch_special_searcher search_mgr; private final Srch_qarg_mgr qargs_mgr;
private Xow_domain_itm[] search_domain_ary;
public Xows_page__search(Xowe_wiki wiki) {
public Srch_special_page(Xowe_wiki wiki) {
this.ev_mgr = GfoEvMgr.new_(this);
this.app = wiki.Appe();
this.wiki_domain = wiki.Domain_itm();
this.search_mgr = new Xows_core(wiki.Appe().Wiki_mgr());
this.ev_mgr = GfoEvMgr.new_(this);
this.search_mgr = new Srch_special_searcher(wiki.Appe().Wiki_mgr());
this.search_api = wiki.Appe().Api_root().Special().Search();
this.qargs_mgr = new Srch_qarg_mgr(app.Gui_mgr().Search_cfg().Ns_mgr());
GfoEvMgr_.SubSame_many(search_api, this, Xoapi_search.Evt_multi_wikis_changed, Xoapi_search.Evt_multi_wikis_changed);
}
public GfoEvMgr EvMgr() {return ev_mgr;} private GfoEvMgr ev_mgr;
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__search;}
public GfoEvMgr EvMgr() {return ev_mgr;} private final GfoEvMgr ev_mgr;
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__search;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
if (search_domain_ary == null) Multi_wikis_changed();
// get args from urls while applying defaults from search_cfg
Srch_search_cfg search_cfg = wiki.Appe().Gui_mgr().Search_cfg();
qargs_mgr.Clear();
qargs_mgr.Parse(search_cfg.Args_default());
qargs_mgr.Parse(url.Qargs_ary());
qargs_mgr.Ns_mgr().Add_main_if_empty();
// get search_raw
byte[] search_raw = qargs_mgr.Search_raw();
if (search_raw == null) { // search is not in qarg; EX:Special:Search?search=Earth
search_raw = ttl.Leaf_txt_wo_qarg(); // assume search is in leaf; EX: Special:Search/Earth
qargs_mgr.Search_raw_(search_raw);
}
if (Bry_.Len_eq_0(search_raw)) return; // emptry String; exit now, else null ref error; DATE:2015-08-11
if ( search_cfg.Auto_wildcard() // add * automatically if option set
&& wiki.Db_mgr().Tid() == gplx.xowa.wikis.dbs.Xodb_mgr_sql.Tid_sql // only apply to sql
&& Bry_find_.Find_fwd(search_raw, Srch_search_addon.Wildcard__star) == -1 // search term does not have asterisk
)
search_raw = Bry_.Add(search_raw, Srch_search_addon.Wildcard__star);
// get page directly from url
boolean fulltext_invoked = url.Qargs_mgr().Match(Qarg__fulltext, Qarg__fulltext__y);
Xoa_ttl search_ttl = Xoa_ttl.parse(wiki, search_raw);
Xoae_page search_page = page;
if ( !fulltext_invoked
&& !Bry_.Eq(search_raw, Xows_special_meta_.Itm__search.Ttl_bry())) // do not lookup self else stack overflow; happens when going directly to Special:Search (from history)
search_page = wiki.Data_mgr().Get_page(search_ttl, false); // try to find page; EX:Special:Search?search=Earth -> en.w:Earth; needed for search suggest
// page not found, or explicit_search invoked
if (search_page.Missing() || fulltext_invoked) {
if (qargs_mgr.Cancel() != null) { // cancel any existing searches
search_mgr.Search__cancel(qargs_mgr.Cancel());
page.Tab_data().Cancel_show_y_();
return;
}
page.Html_data().Html_restricted_n_();
page.Html_data().Xtn_search_text_(search_raw);
Srch_search_qry qry = Srch_search_qry.New__search_page(search_domain_ary, wiki, search_cfg, qargs_mgr.Simple_search(), search_raw, qargs_mgr.Slab_idx(), search_api.Results_per_page());
search_mgr.Search(wiki, page, search_api.Async_db(), search_domain_ary, qry);
}
// page found; return it;
else {
wiki.Parser_mgr().Parse(search_page, true);
page.Data_raw_(search_page.Data_raw());
if (page.Root() != null) // NOTE: null when going from w:Earth -> q:Earth; DATE:2013-03-20
page.Root().Data_htm_(search_page.Root().Data_htm());
page.Ttl_(search_ttl).Url_(Xoa_url.new_(wiki.Domain_bry(), search_ttl.Full_txt_w_ttl_case())).Redirected_(true);
}
}
private void Multi_wikis_changed() {
Xow_domain_crt_itm crt = search_api.Multi_wikis_crt(wiki_domain);
this.search_domain_ary = Get_by_crt(app.Usere().Wiki().Xwiki_mgr(), wiki_domain, crt);
@@ -44,54 +98,6 @@ public class Xows_page__search implements Xows_page, GfoInvkAble, GfoEvObj {
Xow_domain_sorter__manual sorter = new Xow_domain_sorter__manual(wiki_domain, ary);
Xow_domain_sorter__manual.Sort(sorter, search_domain_ary);
}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
if (wiki.Domain_tid() == Xow_domain_tid_.Int__home) return; // do not allow search in home wiki; will throw null ref error b/c no search_ttl dirs
if (search_domain_ary == null) Multi_wikis_changed();
// get args
Xog_search_suggest_mgr search_suggest_mgr = wiki.Appe().Gui_mgr().Search_suggest_mgr();
args_mgr.Clear();
args_mgr.Parse(search_suggest_mgr.Args_default());
args_mgr.Parse(url.Qargs_ary());
args_mgr.Ns_mgr().Add_main_if_empty();
// get search_bry
byte[] search_bry = args_mgr.Search_bry();
if (search_bry == null) { // search is not in qarg; EX:Special:Search?search=Earth
search_bry = ttl.Leaf_txt_wo_qarg(); // assume search is in leaf; EX: Special:Search/Earth
args_mgr.Search_bry_(search_bry);
}
if (Bry_.Len_eq_0(search_bry)) return; // emptry String; exit now, else null ref error; DATE:2015-08-11
if ( search_suggest_mgr.Auto_wildcard() // add * automatically if option set
&& wiki.Db_mgr().Tid() == gplx.xowa.wikis.dbs.Xodb_mgr_sql.Tid_sql // only apply to sql
&& Bry_find_.Find_fwd(search_bry, Byte_ascii.Star) == -1 // search term does not have asterisk
)
search_bry = Bry_.Add(search_bry, Byte_ascii.Star);
// url.Page_bry_(Bry_.Add(Xows_special_meta_.Itm__search.Ttl_bry(), Byte_ascii.Slash_bry, search_bry));// HACK: need to re-set Page b/c href_parser does not eliminate qargs; DATE:2013-02-08
// search wiki
Xoa_ttl search_ttl = Xoa_ttl.parse(wiki, search_bry);
Xoae_page search_page = page;
if (!Bry_.Eq(search_bry, Xows_special_meta_.Itm__search.Ttl_bry())) // do not lookup page else stack overflow; happens when going directly to Special:Search (from history)
search_page = wiki.Data_mgr().Get_page(search_ttl, false); // try to find page; EX:Special:Search?search=Earth -> en.w:Earth; needed for search suggest
// page not found, or explicit_search invoked
if (search_page.Missing() || url.Qargs_mgr().Match(Qarg__fulltext, Qarg__fulltext__y)) {
if (args_mgr.Cancel() != null) {
search_mgr.Cancel(args_mgr.Cancel());
page.Tab_data().Cancel_show_y_();
return;
}
page.Html_data().Html_restricted_n_();
page.Html_data().Xtn_search_text_(search_bry);
Srch_qry qry = new Srch_qry(search_bry, args_mgr.Paging_idx(), search_api.Results_per_page(), args_mgr.Ns_mgr(), search_api.Async_db(), search_domain_ary);
search_mgr.Search(wiki, page, qry);
}
// page found; return it;
else {
wiki.Parser_mgr().Parse(search_page, true);
page.Data_raw_(search_page.Data_raw());
if (page.Root() != null) // NOTE: null when going from w:Earth -> q:Earth; DATE:2013-03-20
page.Root().Data_htm_(search_page.Root().Data_htm());
page.Ttl_(search_ttl).Url_(Xoa_url.new_(wiki.Domain_bry(), search_ttl.Full_txt())).Redirected_(true);
}
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Xoapi_search.Evt_multi_wikis_changed)) Multi_wikis_changed();
else if (ctx.Match(k, Xoapi_search.Evt_multi_sorts_changed)) Multi_sorts_changed();
@@ -100,12 +106,15 @@ public class Xows_page__search implements Xows_page, GfoInvkAble, GfoEvObj {
}
public static final byte Match_tid_all = 0, Match_tid_bgn = 1;
public static final byte Version_null = 0, Version_1 = 1, Version_2 = 2;
private static final byte[] Qarg__fulltext = Bry_.new_a7("fulltext"), Qarg__fulltext__y = Bry_.new_a7("y");
private static final byte[] Qarg__fulltext = Bry_.new_a7("fulltext"), Qarg__fulltext__y = Bry_.new_a7("y");
private static Xow_domain_itm[] Get_by_crt(gplx.xowa.wikis.xwikis.Xow_xwiki_mgr xwiki_mgr, Xow_domain_itm cur, gplx.xowa.wikis.domains.crts.Xow_domain_crt_itm crt) {
List_adp rv = List_adp_.new_();
int len = xwiki_mgr.Len();
for (int i = 0; i < len; ++i) {
gplx.xowa.wikis.xwikis.Xow_xwiki_itm xwiki = xwiki_mgr.Get_at(i); if (!xwiki.Offline()) continue;
gplx.xowa.wikis.xwikis.Xow_xwiki_itm xwiki = xwiki_mgr.Get_at(i);
if ( !xwiki.Offline() // note that filters are broad (*.wiktionary); skip offline wikis which won't be available on system
&& xwiki.Domain_tid() != Xow_domain_tid_.Int__home) // note that home is marked "offline" so it won't show up in wikis sidebar
continue;
Xow_domain_itm domain_itm = Xow_domain_itm_.parse(xwiki.Domain_bry());
if (crt.Matches(cur, domain_itm)) rv.Add(domain_itm);
}

View File

@@ -0,0 +1,53 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.specials; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.xowa.wikis.*; import gplx.xowa.wikis.domains.*;
import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.specials.htmls.*; import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_special_searcher {
private final Xoae_wiki_mgr wiki_mgr;
private final Ordered_hash cancel_hash = Ordered_hash_.New_bry();
private final Srch_html_page_bldr html_page_bldr = new Srch_html_page_bldr();
public Srch_special_searcher(Xoae_wiki_mgr wiki_mgr) {this.wiki_mgr = wiki_mgr;}
public void Search(Xow_wiki search_wiki, Xoae_page page, boolean search_is_async, Xow_domain_itm[] domains_ary, Srch_search_qry qry) {
Bry_bfr tmp_bfr = Bry_bfr.new_();
html_page_bldr.Init_by_wiki(search_wiki, search_wiki.Lang().Num_mgr(), qry);
int domains_len = domains_ary.length;
for (int i = 0; i < domains_len; ++i) {
Xow_domain_itm domain = domains_ary[i];
try {
Xowe_wiki wiki = wiki_mgr.Get_by_or_make(domain.Domain_bry()); wiki.Init_assert();
byte[] key = gplx.langs.htmls.Gfh_utl.Encode_id_as_bry(Bry_.Add(qry.Phrase.Orig, Byte_ascii.Pipe_bry, qry.Ns_mgr.To_hash_key(), Byte_ascii.Pipe_bry, wiki.Domain_bry()));
Srch_special_cmd cmd = new Srch_special_cmd(this, qry, wiki, page.Tab_data().Close_mgr(), page.Tab_data().Tab().Html_itm(), key, search_is_async);
cancel_hash.Add(key, cmd);
cmd.Search(); // do search; note if async, will return immediately
html_page_bldr.Bld_tbl(tmp_bfr, new Srch_rslt_list(), key, cmd.wiki.Domain_bry(), search_is_async, qry.Slab_bgn, qry.Slab_end);
} catch (Exception e) {Xoa_app_.Usr_dlg().Warn_many("", "", "search:wiki failed; wiki=~{0} err=~{1}", domain.Domain_str(), Err_.Message_lang(e));} // handle bad wikis, like "en.wikipedia.org-old"; DATE:2015-04-24
}
// generate html; note if async, this will just generate the page header
page.Data_raw_(html_page_bldr.Bld_page(tmp_bfr.To_bry_and_clear()));
}
public void Search__done(Srch_special_cmd cmd) {
cancel_hash.Del(cmd.key);
}
public void Search__cancel(byte[] cmd_key) {
Srch_special_cmd cmd = (Srch_special_cmd)cancel_hash.Get_by(cmd_key); // if (cmd == null) return; // ignore false calls to cancel
cmd.On_cancel();
cancel_hash.Del(cmd.key);
}
}

View File

@@ -15,11 +15,11 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*; import gplx.xowa.wikis.tdbs.*; import gplx.xowa.wikis.data.tbls.*;
public class Xosrh_core_tst {
//namespace gplx.xowa.addons.searchs.v1s {
// import org.junit.*; using gplx.xowa.wikis.tdbs; using gplx.xowa.wikis.data.tbls;
// public class Xosrh_core_tst {
// @Before public void Init() {fxt.Clear();} private Xos_search_mgr_fxt fxt = new Xos_search_mgr_fxt();
@Test public void Basic() {
// @Test public void Basic() {
// fxt.Init_basic();
// fxt.Test_search_exact("b2", "B2_22", "B2_12", "B2__2");
// fxt.Test_search_exact("a" , "A___0");
@@ -27,7 +27,7 @@ public class Xosrh_core_tst {
// fxt.Test_search_exact("d"); // missing: end
// fxt.Test_search_exact("$"); // missing: bgn
// fxt.Test_search_match_bgn("b*", "B3_23", "B2_22", "B1_21", "B3_13", "B2_12", "B1_11", "B3__3", "B2__2", "B1__1");
}
// }
// @Test public void Page_size() {
// fxt.Init_basic();
// fxt.Search_mgr().Page_mgr().Itms_per_page_(1);
@@ -37,9 +37,9 @@ public class Xosrh_core_tst {
// fxt.Test_search("b*", 3, "B3_13");
// }
// @Test public void Url() {
// Xoa_url url = Xoa_url_parser_old.Parse_url(fxt.App(), fxt.Wiki(), "Special:Search/Abc?fulltext=y&xowa_sort=len_desc");
// Xoa_url url = Xow_url_parser_old.Parse_url(fxt.App(), fxt.Wiki(), "Special:Search/Abc?fulltext=y&xowa_sort=len_desc");
// fxt.Search_mgr().Args_mgr().Clear().Parse(url.Args());
// Tfds.Eq(Xosrh_rslt_itm_sorter.Tid_len_dsc, fxt.Search_mgr().Args_mgr().Sort_tid());
// Tfds.Eq(Srch_rslt_row_sorter.Tid_len_dsc, fxt.Search_mgr().Args_mgr().Sort_tid());
// }
// @Test public void Url_arg_title() {// http://en.wikipedia.org/wiki/Special:Search/Earth?fulltext=yes&title=Mars
// fxt.Test_url_search_bry("Special:Search?fulltext=y&search=Abc" , "Abc"); // query arg
@@ -77,25 +77,25 @@ public class Xosrh_core_tst {
//// @Test public void Page_next() {
//// fxt.Init_basic();
//// fxt.Search_mgr().Page_size_(1);
//// fxt.Test_search(Xows_page__search.Match_tid_all, "B1", 0, "B1 1");
//// fxt.Test_search(Xows_page__search.Match_tid_all, "B1", 1, "B1 11");
//// fxt.Test_search(Srch_special_page.Match_tid_all, "B1", 0, "B1 1");
//// fxt.Test_search(Srch_special_page.Match_tid_all, "B1", 1, "B1 11");
//// }
//// @Test public void Misc_url() {
//// fxt.Init_basic();
//// fxt.Search_mgr().Page_size_(1);
//// fxt.Expd_address_page_("Special:Search/B1");
//// fxt.Test_search(Xows_page__search.Match_tid_all, "B1", 0, "B1 1");
//// fxt.Test_search(Srch_special_page.Match_tid_all, "B1", 0, "B1 1");
//// }
// @Test public void Sort_defaults_to_len_desc() {
// fxt.Init_basic();
// fxt.Search_mgr().Page_mgr().Itms_per_page_(3);
// fxt.Test_search2(Xows_page__search.Match_tid_bgn, "b" , 0, Xosrh_rslt_itm_sorter.Tid_ttl_asc , "B1_11", "B1_21", "B1__1"); // sort by name; note that _ sorts after alphabet
// fxt.Test_search2(Xows_page__search.Match_tid_bgn, "b" , 1, Xosrh_rslt_itm_sorter.Tid_none , "B2_12", "B2_22", "B2__2"); // sort by name still; next page should not reset
// fxt.Test_search2(Xows_page__search.Match_tid_bgn, "b2" , 0, Xosrh_rslt_itm_sorter.Tid_none , "B2_22", "B2_12", "B2__2"); // sort by len desc; new search should reset
// fxt.Test_search2(Srch_special_page.Match_tid_bgn, "b" , 0, Srch_rslt_row_sorter.Tid_ttl_asc , "B1_11", "B1_21", "B1__1"); // sort by name; note that _ sorts after alphabet
// fxt.Test_search2(Srch_special_page.Match_tid_bgn, "b" , 1, Srch_rslt_row_sorter.Tid_none , "B2_12", "B2_22", "B2__2"); // sort by name still; next page should not reset
// fxt.Test_search2(Srch_special_page.Match_tid_bgn, "b2" , 0, Srch_rslt_row_sorter.Tid_none , "B2_22", "B2_12", "B2__2"); // sort by len desc; new search should reset
// }
}
// }
// class Xos_search_mgr_fxt {
// Xoae_app app; Xowe_wiki wiki; Bry_bfr bfr = Bry_bfr.reset_(500); Xows_page__search search_mgr;
// Xoae_app app; Xowe_wiki wiki; Bry_bfr bfr = Bry_bfr.reset_(500); Srch_special_page search_mgr;
// public Xoae_app App() {return app;}
// public Xowe_wiki Wiki() {return wiki;}
// public Xobl_regy_itm regy_itm_(int id, String bgn, String end, int count) {return new Xobl_regy_itm(id, Bry_.new_u8(bgn), Bry_.new_u8(end), count);}
@@ -160,19 +160,19 @@ public class Xosrh_core_tst {
// }
// public void Clear() {
// Io_mgr.Instance.InitEngine_mem();
// app = Xoa_app_fxt.app_();
// wiki = Xoa_app_fxt.wiki_tst_(app);
// app = Xoa_app_fxt.Make__app__edit();
// wiki = Xoa_app_fxt.Make__wiki__edit(app);
// search_mgr = wiki.Special_mgr().Page_search();
// wiki.Appe().Gui_mgr().Search_suggest_mgr().Args_default_str_("ns*=1"); // WORKAROUND: xdat fmt does not store ns with search data; pages will be retrieved with ns_id = null; force ns_all (instead of allowing ns_main default);
// }
// public Xows_page__search Search_mgr() {return search_mgr;}
// public Srch_special_page Search_mgr() {return search_mgr;}
// public void Test_url_search_bry(String url_str, String expd) {
// Xoa_url url = Xoa_url_parser_old.Parse_url(app, wiki, url_str);
// Xoa_url url = Xow_url_parser_old.Parse_url(app, wiki, url_str);
// search_mgr.Args_mgr().Clear().Parse(url.Args());
// Tfds.Eq(expd, String_.new_u8(search_mgr.Args_mgr().Search_bry()));
// }
// public void Test_url__ns(String url_str, String expd) {
// Xoa_url url = Xoa_url_parser_old.Parse_url(app, wiki, url_str);
// Xoa_url url = Xow_url_parser_old.Parse_url(app, wiki, url_str);
// search_mgr.Args_mgr().Clear().Parse(url.Args());
// Tfds.Eq(expd, String_.new_a7(search_mgr.Args_mgr().Ns_mgr().Xto_hash_key()));
// }
@@ -197,8 +197,8 @@ public class Xosrh_core_tst {
// }
// public void Test_search2(byte match_tid, String ttl_str, int page_idx, byte sort_tid, params String[] expd_ary) {
// Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b128();
// Xoa_url_parser_old url_parser = new Xoa_url_parser_old();
// byte[] url_raw = Bry_.new_a7("Special:Search/" + ttl_str + ((match_tid == Xows_page__search.Match_tid_all) ? "" : "*") + "?fulltext=y" + Xosrh_rslt_itm_sorter.Xto_url_arg(sort_tid) + "&xowa_page_size=1&xowa_page_index=" + page_idx);
// Xow_url_parser_old url_parser = new Xow_url_parser_old();
// byte[] url_raw = Bry_.new_a7("Special:Search/" + ttl_str + ((match_tid == Srch_special_page.Match_tid_all) ? "" : "*") + "?fulltext=y" + Srch_rslt_row_sorter.Xto_url_arg(sort_tid) + "&xowa_page_size=1&xowa_page_index=" + page_idx);
// Xoa_url url = url_parser.Parse(url_raw);
// Xoa_ttl ttl = Xoa_ttl.parse(wiki, url_raw);
// Xoae_page page = wiki.Ctx().Page();
@@ -220,3 +220,4 @@ public class Xosrh_core_tst {
// interface Xobl_data_itm {
// void Srl_save(Bry_bfr bfr);
// }
//}

View File

@@ -15,10 +15,10 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
package gplx.xowa.addons.searchs.specials; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*;
import gplx.core.primitives.*; import gplx.xowa.langs.*;
import gplx.xowa.wikis.domains.*; import gplx.xowa.wikis.domains.crts.*;
class Xow_domain_sorter__manual implements gplx.core.lists.ComparerAble {
public class Xow_domain_sorter__manual implements gplx.core.lists.ComparerAble {
private final Xow_domain_itm cur_domain;
private final Xow_domain_crt_itm[] ary; private final int ary_len;
public Xow_domain_sorter__manual(Xow_domain_itm cur_domain, Xow_domain_crt_itm[] ary) {
@@ -118,4 +118,4 @@ class Xow_domain_sorter__manual_lang implements gplx.core.lists.ComparerAble {
}
return new Xow_domain_sorter__manual_lang(id_ints);
}
}
}

View File

@@ -0,0 +1,98 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.specials.htmls; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.specials.*;
import gplx.core.brys.fmtrs.*;
import gplx.langs.htmls.*; import gplx.xowa.htmls.core.htmls.utls.*; import gplx.xowa.langs.numbers.*;
import gplx.xowa.addons.searchs.specials.*; import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_html_page_bldr {
private final Bry_bfr tmp_bfr = Bry_bfr.new_(255);
private Srch_search_qry qry; private Xow_wiki wiki; private Xol_num_mgr num_mgr;
private int slab_idx;
private Xoh_lnki_bldr lnki_bldr; private Xoh_anchor_kv_bldr self_lnkr = new Xoh_anchor_kv_bldr(); private Srch_html_row_bldr html_row_bldr;
public void Init_by_wiki(Xow_wiki wiki, Xol_num_mgr num_mgr, Srch_search_qry qry) {
this.wiki = wiki; this.num_mgr = num_mgr; this.qry = qry;
this.lnki_bldr = wiki.App().Html__lnki_bldr();
int slab_len = qry.Slab_end - qry.Slab_bgn;
this.slab_idx = qry.Slab_bgn / slab_len;
this.html_row_bldr = new Srch_html_row_bldr(lnki_bldr);
self_lnkr.Init_w_qarg(tmp_bfr.Add(Bry__special_search).Add(qry.Phrase.Orig).Add(Bry__fulltext).To_bry_and_clear());
}
public byte[] Bld_page(byte[] html_tbls_bry) {
byte[] rslts_hdr = fmtr_rslts.Bld_bry_many(tmp_bfr, num_mgr.Format_num(qry.Slab_bgn + List_adp_.Base1), num_mgr.Format_num(qry.Slab_end), qry.Phrase.Orig);
byte[] option_link = lnki_bldr.Href_(Bry_.new_a7("home"), wiki.Ttl_parse(Bry_.new_a7("Options/Search"))).Img_16x16(Xoh_img_path.Img_option).Bld_to_bry(); // HOME
fmtr_page.Bld_bfr_many(tmp_bfr, rslts_hdr, option_link, Bld_paging_link(Bool_.N), Bld_paging_link(Bool_.Y), html_tbls_bry);
return tmp_bfr.To_bry_and_clear();
}
public void Bld_tbl(Bry_bfr bfr, Srch_rslt_list rslt_list, byte[] cmd_key, byte[] wiki_domain, boolean searching_db, int slab_bgn, int slab_end) {
html_row_bldr.Init(rslt_list, slab_bgn, slab_end);
byte[] search_link = lnki_bldr.Href_(wiki_domain, wiki.Ttl_parse(self_lnkr.Bld_to_bry())).Caption_(wiki_domain).Img_16x16(Xoh_img_path.Img_search).Img_pos_is_left_(Bool_.Y).Bld_to_bry();
fmtr_tbl.Bld_bfr_many(bfr, search_link, searching_db ? Bld_cancel_link(wiki_domain, cmd_key) : Bry_.Empty, Bry_hdr_len, Bry_hdr_ttl, Srch_html_row_wkr.Gen_insert_key(wiki_domain), html_row_bldr);
}
private byte[] Bld_cancel_link(byte[] domain, byte[] cmd_key) {
lnki_bldr.Id_(Bry_.Add(Bry_.new_a7("xowa_cancel_"), domain));
lnki_bldr.Href_(wiki, self_lnkr.Add_int(Srch_qarg_mgr.Bry__slab_idx, slab_idx).Add_bry(Srch_qarg_mgr.Bry__cancel, cmd_key).Bld_to_bry());
lnki_bldr.Title_(Bry_cancel);
lnki_bldr.Img_16x16(Xoh_img_path.Img_cancel);
return lnki_bldr.Bld_to_bry();
}
public byte[] Bld_paging_link(boolean fwd) {
byte[] title = null, img_path = Bry_.Empty;
boolean img_pos_is_left = true;
int qarg_slab_idx = slab_idx;
if (fwd) {
++qarg_slab_idx;
// if (slab_idx > qry.Page_max()) return Gfh_entity_.Nbsp_num_bry;
img_pos_is_left = false;
img_path = Xoh_img_path.Img_go_fwd;
title = Bry_paging_fwd;
}
else {
--qarg_slab_idx;
if (qarg_slab_idx < 0) return Gfh_entity_.Nbsp_num_bry;
img_path = Xoh_img_path.Img_go_bwd;
title = Bry_paging_bwd;
}
return lnki_bldr.Title_(title).Href_(wiki, self_lnkr.Add_int(Srch_qarg_mgr.Bry__slab_idx, qarg_slab_idx).Bld_to_bry()).Img_16x16(img_path).Img_pos_is_left_(img_pos_is_left).Caption_(title).Bld_to_bry();
}
private static final Bry_fmtr fmtr_page = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "~{rslts_hdr}<span style='margin-left:10px'>~{option_link}</span>"
, "<div id='xowa_panel_top' style='width:60%;'><div style='float:right;'><span>~{bwd_a}</span><span style='margin-left:10px'>~{fwd_a}</span></div></div>~{tbls}"
, "<div id='xowa_panel_bot' style='width:60%;'><div style='float:right;'><span>~{bwd_a}</span><span style='margin-left:10px'>~{fwd_a}</span></div></div>"
), "rslts_hdr", "option_link", "bwd_a", "fwd_a", "tbls");
private static final Bry_fmtr fmtr_tbl = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "<table class='wikitable sortable' style='width:60%;'>"
, " <tr>"
, " <th colspan='2' style='text-align:left'>~{wiki}<span style='float:right'>~{cancel}</span>"
, " </th>"
, " </tr>"
, " <tr>"
, " <th width='100'>~{hdr_len}"
, " </th>"
, " <th>~{hdr_ttl}"
, " </th>"
, " </tr>~{rows}"
, " <tr id='~{insert_key}' style='display:none;'>"
, " </tr>"
, "</table>"
), "wiki", "cancel", "hdr_len", "hdr_ttl", "insert_key", "rows");
private static final Bry_fmtr fmtr_rslts = Bry_fmtr.new_("Results <b>~{bgn}</b> of <b>~{end}</b> for <b>~{raw}</b>", "bgn", "end", "raw");
private static final byte[] Bry_paging_fwd = Bry_.new_a7("Next"), Bry_paging_bwd = Bry_.new_a7("Previous"), Bry_cancel = Bry_.new_a7("Stop searching")
, Bry_hdr_len = Bry_.new_a7("Page score"), Bry_hdr_ttl = Bry_.new_a7("Page title")
;
private final byte[] Bry__special_search = Bry_.new_a7("Special:Search/"), Bry__fulltext = Bry_.new_a7("?fulltext=y");
}

View File

@@ -15,12 +15,13 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
package gplx.xowa.addons.searchs.specials.htmls; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.specials.*;
import org.junit.*; import gplx.xowa.htmls.core.htmls.utls.*; import gplx.xowa.wikis.tdbs.*;
import gplx.xowa.wikis.domains.*;
import gplx.xowa.wikis.data.tbls.*;
public class Xows_html_wkr_tst {
@Before public void init() {fxt.Clear();} private Xows_html_wkr_fxt fxt = new Xows_html_wkr_fxt();
import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_html_page_bldr_tst {
@Before public void init() {fxt.Clear();} private Srch_html_page_bldr_fxt fxt = new Srch_html_page_bldr_fxt();
@Test public void Paging() {
fxt.Test_paging(Bool_.Y, 1, "<a href='/site/en.wikipedia.org/wiki/Special:Search/A%3Ffulltext%3Dy%26xowa_page_index%3D2' title='Next'>Next<img src='file:///mem/xowa/bin/any/xowa/file/app.general/go_fwd.png' width='16' height='16'/></a>");
fxt.Test_paging(Bool_.N, 1, "<a href='/site/en.wikipedia.org/wiki/Special:Search/A%3Ffulltext%3Dy%26xowa_page_index%3D0' title='Previous'><img src='file:///mem/xowa/bin/any/xowa/file/app.general/go_bwd.png' width='16' height='16'/>Previous</a>");
@@ -28,15 +29,15 @@ public class Xows_html_wkr_tst {
fxt.Test_paging(Bool_.N, 0, "&#160;");
}
@Test public void Rows() {
fxt.Test_rows(new Srch_rslt_itm[] {fxt.Make_row(10, "A"), fxt.Make_row(20, "B")}, String_.Concat_lines_nl_skip_last
fxt.Test_rows(new Srch_rslt_row[] {fxt.Make_row(10, "A"), fxt.Make_row(20, "B")}, String_.Concat_lines_nl_skip_last
( ""
, " <tr id='w.7CA'>"
, " <tr id='w.7C1'>"
, " <td style='padding-right:5px; vertical-align:top; text-align:right;'>10"
, " </td>"
, " <td style='padding-left:5px; vertical-align:top;'><a href='/site/w/wiki/A' title='A'>A</a>"
, " </td>"
, " </tr>"
, " <tr id='w.7CB'>"
, " <tr id='w.7C2'>"
, " <td style='padding-right:5px; vertical-align:top; text-align:right;'>20"
, " </td>"
, " <td style='padding-left:5px; vertical-align:top;'><a href='/site/w/wiki/B' title='B'>B</a>"
@@ -45,34 +46,40 @@ public class Xows_html_wkr_tst {
));
}
}
class Xows_html_wkr_fxt {
private Xoae_app app; private Xowe_wiki wiki; private Xows_html_wkr html_mgr; private final Bry_bfr tmp_bfr = Bry_bfr.new_(255);
public Xows_html_wkr_fxt Clear() {
class Srch_html_page_bldr_fxt {
private Xoae_app app; private Xowe_wiki wiki; private Srch_html_page_bldr html_mgr; private final Bry_bfr tmp_bfr = Bry_bfr.new_(255);
private int page_id;
public Srch_html_page_bldr_fxt Clear() {
if (app == null) {
app = Xoa_app_fxt.app_();
wiki = Xoa_app_fxt.wiki_tst_(app);
html_mgr = new Xows_html_wkr();
app = Xoa_app_fxt.Make__app__edit();
wiki = Xoa_app_fxt.Make__wiki__edit(app);
html_mgr = new Srch_html_page_bldr();
}
page_id = 0;
return this;
}
public void Test_paging(boolean fwd, int paging_idx, String expd) {
Srch_qry qry = new Srch_qry(Bry_.new_a7("A"), paging_idx, 100, new Xows_ns_mgr(), true, new Xow_domain_itm[] {Xow_domain_itm_.parse(wiki.Domain_bry())});
qry.page_max = 2;
public void Test_paging(boolean fwd, int slab_idx, String expd) {
byte[] search_orig = Bry_.new_a7("A");
Srch_search_qry qry = Srch_search_qry.New__search_page(Xow_domain_itm_.Ary_empty, wiki, app.Gui_mgr().Search_cfg(), Bool_.N, search_orig, slab_idx, 100);
html_mgr.Init_by_wiki(wiki, wiki.Lang().Num_mgr(), qry);
byte[] paging_link = html_mgr.Paging_link(fwd);
byte[] paging_link = html_mgr.Bld_paging_link(fwd);
Tfds.Eq(expd, String_.new_a7(paging_link));
}
public void Test_rows(Srch_rslt_itm[] rows, String expd) {
Srch_rslt_list rslt = new Srch_rslt_list();
Xows_html_row html_row = new Xows_html_row(wiki.App().Html__lnki_bldr());
html_row.Init(rslt);
public void Test_rows(Srch_rslt_row[] rows, String expd) {
Srch_rslt_list rslts = new Srch_rslt_list();
Srch_html_row_bldr row_bldr = new Srch_html_row_bldr(wiki.App().Html__lnki_bldr());
row_bldr.Init(rslts, 0, rows.length);
for (int i = 0; i < rows.length; ++i)
rslt.Add(rows[i]);
html_row.Bfr_arg__add(tmp_bfr);
rslts.Add(rows[i]);
row_bldr.Bfr_arg__add(tmp_bfr);
Tfds.Eq_str_lines(expd, tmp_bfr.To_str_and_clear());
}
public Srch_rslt_itm Make_row(int len, String ttl_str) {
public Srch_rslt_row Make_row(int len, String ttl_str) {
byte[] wiki_bry = Bry_.new_a7("w");
byte[] ttl_bry = Bry_.new_u8(ttl_str);
return new Srch_rslt_itm(Bry_.new_a7("w"), wiki.Ttl_parse(ttl_bry), 1, len);
++page_id;
Srch_rslt_row rv = new Srch_rslt_row(Srch_rslt_row.Bld_key(wiki_bry, page_id), wiki_bry, wiki.Ttl_parse(ttl_bry), gplx.xowa.wikis.nss.Xow_ns_.Tid__main, ttl_bry, page_id, len, len, Srch_rslt_row.Page_redirect_id_null);
rv.Page_ttl_highlight = rv.Page_ttl.Full_txt_w_ttl_case();
return rv;
}
}

View File

@@ -0,0 +1,52 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.searchs.specials.htmls; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.specials.*;
import gplx.xowa.htmls.core.htmls.utls.*; import gplx.langs.htmls.*;
import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_html_row_bldr implements gplx.core.brys.Bfr_arg {
private final Xoh_lnki_bldr lnki_bldr;
private Srch_rslt_list rslt_list; private int slab_bgn, slab_end;
private final Object thread_lock = new Object();
public Srch_html_row_bldr(Xoh_lnki_bldr lnki_bldr) {this.lnki_bldr = lnki_bldr;}
public Srch_html_row_bldr Init(Srch_rslt_list rslt_list, int slab_bgn, int slab_end) {this.rslt_list = rslt_list; this.slab_bgn = slab_bgn; this.slab_end = slab_end; return this;}
public void Bfr_arg__add(Bry_bfr bfr) { // <a href="/wiki/A" title="A" class="xowa-visited">A</a>
int rslts_len = rslt_list.Len();
for (int i = slab_bgn; i < slab_end; ++i) {
if (i >= rslts_len) return;
Srch_rslt_row row = rslt_list.Get_at(i);
Bld_html(bfr, row);
}
}
public void Bld_html(Bry_bfr bfr, Srch_rslt_row row) {
synchronized (thread_lock) {
lnki_bldr.Href_(row.Wiki_bry, row.Page_ttl);
lnki_bldr.Title_(row.Page_ttl.Full_txt_w_ttl_case());
lnki_bldr.Caption_direct_(row.Page_ttl_display(Bool_.Y));
fmtr.Bld_many(bfr, Gfh_utl.Encode_id_as_str(row.Key), row.Page_score, lnki_bldr.Bld_to_bry());
}
}
public Bry_fmt Fmtr() {return fmtr;} private final Bry_fmt fmtr = Bry_fmt.Auto(String_.Concat_lines_nl_skip_last
( ""
, " <tr id='~{page_key}'>"
, " <td style='padding-right:5px; vertical-align:top; text-align:right;'>~{page_len}"
, " </td>"
, " <td style='padding-left:5px; vertical-align:top;'>~{lnki}" // SERVER:"<a href='"; DATE:2015-04-16
, " </td>"
, " </tr>"
));
}

View File

@@ -15,56 +15,54 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
package gplx.xowa.addons.searchs.specials.htmls; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.specials.*;
import gplx.langs.htmls.*; import gplx.xowa.files.gui.*;
class Xows_ui_async__html implements Srch_rslt_lnr {
private final Xows_html_row html_row; private final Xog_js_wkr js_wkr;
private final Srch_rslt_itm[] rows; private final int rows_len;
private final Bry_bfr bfr = Bry_bfr.new_(255);
private final byte[] insert_new_key;
private final Cancelable cxl;
public Xows_ui_async__html(Cancelable cxl, Xows_html_row html_row, Xog_js_wkr js_wkr, int paging_len, byte[] wiki) {
this.cxl = cxl;
this.html_row = html_row; this.js_wkr = js_wkr;
this.rows = new Srch_rslt_itm[paging_len];
this.rows_len = paging_len;
import gplx.xowa.addons.searchs.searchers.*; import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_html_row_wkr {
private final Srch_html_row_bldr html_row_bldr; private final Xog_js_wkr js_wkr;
private final Srch_rslt_row[] rows; private final int rows_len;
private final Bry_bfr bfr = Bry_bfr.new_(255);
private final byte[] insert_new_key;
public Srch_html_row_wkr(Srch_html_row_bldr html_row_bldr, Xog_js_wkr js_wkr, int slab_len, byte[] wiki) {
this.html_row_bldr = html_row_bldr; this.js_wkr = js_wkr;
this.rows = new Srch_rslt_row[slab_len];
this.rows_len = slab_len;
this.insert_new_key = Gen_insert_key(wiki);
}
public void Notify_rslt_found(Srch_rslt_itm new_row) {
Srch_rslt_itm last_row = rows[rows_len - 1];
public void Set(int i, Srch_rslt_row row) {rows[i] = row;}
public void On_rslt_found(Srch_rslt_row new_row) {
Srch_rslt_row last_row = rows[rows_len - 1];
if (last_row != null) {
if (Compare(new_row, last_row) == CompareAble_.MoreOrSame) return; // new_row is < last_row; exit
}
int new_row_slot = Find_insert_slot(new_row); if (new_row_slot == -1) return;
Srch_rslt_itm insert_row = rows[new_row_slot];
byte[] insert_key = insert_row == null ? insert_new_key : insert_row.key;
Srch_rslt_row insert_row = rows[new_row_slot];
byte[] insert_key = insert_row == null ? insert_new_key : insert_row.Key;
Displace(new_row_slot, new_row);
html_row.Gen_html(bfr, new_row);
html_row_bldr.Bld_html(bfr, new_row);
String html_tbl = bfr.To_str_and_clear();
if (cxl.Canceled()) return;
js_wkr.Html_elem_append_above(Gfh_utl.Encode_id_as_str(insert_key), html_tbl);
if (last_row != null) {
if (cxl.Canceled()) return;
js_wkr.Html_elem_replace_html(Gfh_utl.Encode_id_as_str(last_row.key), "");
js_wkr.Html_elem_replace_html(Gfh_utl.Encode_id_as_str(last_row.Key), "");
}
}
private int Find_insert_slot(Srch_rslt_itm new_row) {
private int Find_insert_slot(Srch_rslt_row new_row) {
for (int i = 0; i < rows_len; ++i) {
Srch_rslt_itm cur_row = rows[i];
Srch_rslt_row cur_row = rows[i];
if (cur_row == null) return i;
if (Compare(new_row, cur_row) == CompareAble_.Less) return i;
}
return -1;
}
private void Displace(int new_row_slot, Srch_rslt_itm new_row) {
private void Displace(int new_row_slot, Srch_rslt_row new_row) {
for (int i = rows_len - 2; i >= new_row_slot; --i) {
rows[i + 1] = rows[i];
}
rows[new_row_slot] = new_row;
}
private int Compare(Srch_rslt_itm lhs, Srch_rslt_itm rhs) {
return -Int_.Compare(lhs.page_len, rhs.page_len);
private int Compare(Srch_rslt_row lhs, Srch_rslt_row rhs) {
return -Int_.Compare(lhs.Page_score, rhs.Page_score);
}
public static byte[] Gen_insert_key(byte[] wiki) {return Bry_.Add(Bry_insert_key, wiki);}
private static final byte[] Bry_insert_key = Bry_.new_a7("xowa_insert_");
private static final byte[] Bry_insert_key = Bry_.new_a7("xowa_insert_");
}

View File

@@ -15,41 +15,45 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*; import gplx.xowa.htmls.core.htmls.utls.*; import gplx.xowa.files.gui.*;
public class Xows_ui_async_tst {
@Before public void init() {fxt.Clear();} private Xows_ui_async_fxt fxt = new Xows_ui_async_fxt();
package gplx.xowa.addons.searchs.specials.htmls; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.searchs.*; import gplx.xowa.addons.searchs.specials.*;
import org.junit.*; import gplx.xowa.htmls.core.htmls.utls.*; import gplx.xowa.files.gui.*; import gplx.xowa.addons.searchs.searchers.rslts.*;
public class Srch_rslt_cbk_tst {
@Before public void init() {fxt.Clear();} private Srch_rslt_cbk_fxt fxt = new Srch_rslt_cbk_fxt();
@Test public void Basic() {
fxt.Test_add(fxt.Make_rslt(50, "L"), fxt.Make_args_append("xowa_insert_w" , "w.7CL")); // insert new
fxt.Test_add(fxt.Make_rslt(30, "N"), fxt.Make_args_append("xowa_insert_w" , "w.7CN")); // insert below last
fxt.Test_add(fxt.Make_rslt(70, "J"), fxt.Make_args_append("w.7CL" , "w.7CJ")); // insert above first
fxt.Test_add(fxt.Make_rslt(60, "K"), fxt.Make_args_append("w.7CL" , "w.7CK")); // insert above mid
fxt.Test_add(fxt.Make_rslt(40, "M"), fxt.Make_args_append("w.7CN" , "w.7CM")); // insert below mid
fxt.Test_add(fxt.Make_rslt(10, "P")); // insert noop
fxt.Test_add(fxt.Make_rslt(10, "P")); // insert noop
fxt.Test_add(fxt.Make_rslt(80, "I"), fxt.Make_args_append("w.7CJ" , "w.7CI") , fxt.Make_args_replace("w.7CN")); // insert displace all
fxt.Test_add(fxt.Make_rslt(61, "K1"), fxt.Make_args_append("w.7CK" , "w.7CK1"), fxt.Make_args_replace("w.7CM")); // insert displace mid
}
}
class Xows_ui_async_fxt {
private Xows_html_row html_row; private static final byte[] Bry_enwiki = Bry_.new_a7("w");
private Xows_ui_async__html async;
class Srch_rslt_cbk_fxt {
private Srch_html_row_bldr html_row; private static final byte[] Bry_enwiki = Bry_.new_a7("w");
private Srch_html_row_wkr async;
private Xog_js_wkr__log js_wkr = new Xog_js_wkr__log();
private Xowe_wiki wiki;
private int page_id;
public void Clear() {
Xoae_app app = Xoa_app_fxt.app_();
this.wiki = Xoa_app_fxt.wiki_(app, "w");
html_row = new Xows_html_row(wiki.App().Html__lnki_bldr());
Xoae_app app = Xoa_app_fxt.Make__app__edit();
this.wiki = Xoa_app_fxt.Make__wiki__edit(app, "w");
html_row = new Srch_html_row_bldr(wiki.App().Html__lnki_bldr());
html_row.Fmtr().Fmt_("~{page_key}");
async = new Xows_ui_async__html(Cancelable_.Never, html_row, js_wkr, 5, Bry_enwiki);
async = new Srch_html_row_wkr(html_row, js_wkr, 5, Bry_enwiki);
page_id = 0;
}
public Srch_rslt_itm Make_rslt(int len, String ttl) {
public Srch_rslt_row Make_rslt(int len, String ttl) {
byte[] ttl_bry = Bry_.new_a7(ttl);
return new Srch_rslt_itm(Bry_enwiki, wiki.Ttl_parse(ttl_bry), 1, len);
++page_id;
byte[] key = Bry_.Add(Bry_enwiki, Byte_ascii.Pipe_bry, ttl_bry); // NOTE: deliberately changing key to use ttl instead of id to make tests more readable
return new Srch_rslt_row(key, Bry_enwiki, wiki.Ttl_parse(ttl_bry), gplx.xowa.wikis.nss.Xow_ns_.Tid__main, ttl_bry, page_id, len, len, Srch_rslt_row.Page_redirect_id_null);
}
public Object[] Make_args_append(String uid, String html) {return Object_.Ary(Xog_js_wkr__log.Proc_append_above, uid, html);}
public Object[] Make_args_replace(String uid) {return Object_.Ary(Xog_js_wkr__log.Proc_replace_html, uid, "");}
public void Test_add(Srch_rslt_itm row, Object[]... expd) {
async.Notify_rslt_found(row);
public void Test_add(Srch_rslt_row row, Object[]... expd) {
async.On_rslt_found(row);
int expd_len = expd.length;
Tfds.Eq(expd_len, js_wkr.Log__len());
for (int i = 0; i < expd_len; ++i) {

View File

@@ -0,0 +1,31 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.sqlite_utils; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*;
public class Sqlite_utils_addon implements Xoax_addon_itm {
public Sqlite_utils_addon(Xow_wiki wiki) {
}
public byte[] Addon__key() {return Key_const;} public static final byte[] Key_const = Bry_.new_a7("xowa.sqlite_utils");
public static Sqlite_utils_addon Get(Xow_wiki wiki) {
Sqlite_utils_addon rv = (Sqlite_utils_addon)wiki.Addon_mgr().Itms__get_or_null(Key_const);
if (rv == null) {
rv = new Sqlite_utils_addon(wiki);
wiki.Addon_mgr().Itms__add(rv);
}
return rv;
}
}

View File

@@ -0,0 +1,86 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.sqlite_utils.bldrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.sqlite_utils.*;
import gplx.dbs.*; import gplx.dbs.qrys.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.wkrs.*;
public class Sqlite_percentile_cmd extends Xob_cmd__base implements Xob_cmd {
private String db_rel_url, tbl_name = "tmp_score"; private int score_max = 100000000; private String select_sql;
private Db_conn conn;
public Sqlite_percentile_cmd(Xob_bldr bldr, Xowe_wiki wiki) {super(bldr, wiki);}
public Sqlite_percentile_cmd Init_by_rel_url(String db_rel_url, String tbl_name, int score_max, String select_sql) {
this.db_rel_url = db_rel_url; this.tbl_name = tbl_name; this.score_max = score_max; this.select_sql = select_sql;
return this;
}
public Sqlite_percentile_cmd Init_by_conn(Db_conn conn, String tbl_name, int score_max, String select_sql) {this.conn = conn; return this.Init_by_rel_url(null, tbl_name, score_max, select_sql);}
public int count;
@Override public String Cmd_key() {return Xob_cmd_keys.Key_util_sqlite_normalize;}
@Override public void Cmd_run() {
wiki.Init_assert();
if (conn == null) {
if (db_rel_url == null) throw Err_.new_("bldr", "db_rel_url can not be empty; EX: 'xowa.page_rank.sqlite3'");
conn = Db_conn_bldr.Instance.Get_or_autocreate(false, wiki.Fsys_mgr().Root_dir().GenSubFil(db_rel_url));
}
Xoa_app_.Usr_dlg().Prog_many("", "", "creating temp_table: tbl=~{0}", tbl_name);
conn.Meta_tbl_drop(tbl_name);
conn.Meta_tbl_create
( Dbmeta_tbl_itm.New(tbl_name
, Dbmeta_fld_itm.new_int("row_rank").Primary_y_().Autonum_y_()
, Dbmeta_fld_itm.new_int("row_key")
, Dbmeta_fld_itm.new_double("row_val")
, Dbmeta_fld_itm.new_double("row_score").Default_(-1)
));
Xoa_app_.Usr_dlg().Prog_many("", "", "filling temp_table: tbl=~{0} sql=~{1}", tbl_name, select_sql);
new Db_attach_mgr(conn, new Db_attach_itm("page_db", wiki.Data__core_mgr().Tbl__page().conn))
.Exec_sql(Bry_fmt.Make_str("INSERT INTO ~{tbl} (row_key, row_val) ~{select}", tbl_name, select_sql));
Xoa_app_.Usr_dlg().Prog_many("", "", "updating row_score: tbl=~{0}", tbl_name);
String score_max_as_str = Dbmeta_fld_itm.To_double_str_by_int(score_max);
this.count = conn.Exec_select_as_int("SELECT Count(*) FROM " + tbl_name, -1); if (count == -1) throw Err_.new_("bldr", "failed to get count; tbl=~{0}", tbl_name);
String count_as_str = Dbmeta_fld_itm.To_double_str_by_int(count);
conn.Exec_sql(Bry_fmt.Make_str("UPDATE ~{tbl} SET row_score = (row_rank * ~{score_max}) / ~{count}", tbl_name, score_max_as_str, count_as_str));
Xoa_app_.Usr_dlg().Prog_many("", "", "resolving ties: tbl=~{0}", tbl_name);
conn.Meta_tbl_drop(tbl_name + "_avg");
conn.Meta_tbl_create
( Dbmeta_tbl_itm.New(tbl_name + "_avg"
, Dbmeta_fld_itm.new_double("row_val").Primary_y_()
, Dbmeta_fld_itm.new_double("row_score")
));
conn.Exec_sql(Bry_fmt.Make_str(String_.Concat_lines_nl_skip_last
( "INSERT INTO ~{tbl}_avg (row_val, row_score)"
, "SELECT row_val"
, ", (Avg(row_rank) * ~{score_max} / ~{count}) AS row_score"
, "FROM ~{tbl}"
, "GROUP BY row_val"
, "HAVING Count(row_val > 1)"
), tbl_name, score_max_as_str, count_as_str));
conn.Exec_sql(Bry_fmt.Make_str(String_.Concat_lines_nl_skip_last
( "UPDATE ~{tbl}"
, "SET row_score = (SELECT row_score FROM ~{tbl}_avg t2 WHERE t2.row_val = ~{tbl}.row_val)"
, "WHERE row_val IN (SELECT row_val FROM ~{tbl}_avg t2)"
), tbl_name));
conn.Meta_idx_create(Xoa_app_.Usr_dlg(), Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, "row_score", "row_key", "row_score"));
}
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__db_rel_url_)) db_rel_url = m.ReadStr("v");
else if (ctx.Match(k, Invk__select_sql_)) select_sql = m.ReadStr("v");
else if (ctx.Match(k, Invk__tbl_name_)) tbl_name = m.ReadStr("v");
else if (ctx.Match(k, Invk__score_max_)) score_max = m.ReadInt("v");
else return GfoInvkAble_.Rv_unhandled;
return this;
}
private static final String Invk__db_rel_url_ = "db_rel_url_", Invk__select_sql_ = "select_sql_", Invk__tbl_name_ = "tbl_name_", Invk__score_max_ = "score_max_";
}

View File

@@ -0,0 +1,41 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.sqlite_utils.bldrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.sqlite_utils.*;
class Statistic_calculator {
private int count;
private double old_avg, cur_avg, old_sum, cur_sum;
public int Count() {return count;}
public double Avg() {return (count > 0) ? cur_avg : 0;}
public double Variance() {return (count > 1) ? cur_sum / (count - 1) : 0;}
public double Stddev() {return Math_.Sqrt(Variance());}
public void Clear() {count = 0;}
public void Push(double x) {
count++;
if (count == 1) {
old_avg = cur_avg = x;
old_sum = 0.0;
}
else {
cur_avg = old_avg + ((x - old_avg) / count);
cur_sum = old_sum + ((x - old_avg) * (x - cur_avg));
old_avg = cur_avg;
old_sum = cur_sum;
}
}
}

View File

@@ -0,0 +1,35 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.sqlite_utils.bldrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.sqlite_utils.*;
class Str_ary_ {
public static String[][] To_str_ary_ary(String v, String val_dlm, String row_dlm) {// "a|b|c`"
String[] rows_ary = String_.Split(v, row_dlm);
int rv_len = rows_ary.length;
String[][] rv = new String[rv_len][];
for (int i = 0; i < rv_len; ++i) {
String row = rows_ary[i];
String[] vals_ary = String_.Split(row, val_dlm);
int vals_len = vals_ary.length;
String[] rv_row = new String[vals_len];
rv[i] = rv_row;
for (int j = 0; j < vals_len; ++j)
rv[i][j] = vals_ary[j];
}
return rv;
}
}

View File

@@ -29,7 +29,7 @@ public class Xoa_app_eval_tst {
class Xoa_app_eval_fxt {
public void Clear() {
if (app == null) {
app = Xoa_app_fxt.app_();
app = Xoa_app_fxt.Make__app__edit();
fmtr = Bry_fmtr.new_();
eval = new Xoa_app_eval();
fmtr.Eval_mgr_(eval);

View File

@@ -31,7 +31,7 @@ public class Xoa_sys_cfg implements GfoInvkAble {
return this;
} private byte[] lang_key = Xol_lang_itm_.Key_en;
public int Options_version() {return options_version;} public Xoa_sys_cfg Options_version_(int v) {options_version = v; return this;} private int options_version = 1;
public KeyVal[] Options_lang_list() {if (options_lang_list == null) options_lang_list = Options_list_lang_.new_(); return options_lang_list;} private KeyVal[] options_lang_list;
public Keyval[] Options_lang_list() {if (options_lang_list == null) options_lang_list = Options_list_lang_.new_(); return options_lang_list;} private Keyval[] options_lang_list;
public long Free_mem_when() {return free_mem_when;} long free_mem_when;
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_version)) return Xoa_app_.Version;
@@ -49,7 +49,7 @@ public class Xoa_sys_cfg implements GfoInvkAble {
, Invk_lang = "lang", Invk_lang_ = "lang_", Invk_lang_list = "lang_list";
}
class Options_list_lang_ {
public static KeyVal[] new_() {
public static Keyval[] new_() {
Ordered_hash translated = Ordered_hash_.New_bry();
List_adp untranslated = List_adp_.new_();
Add_itm_many(translated, Xol_lang_stub_.Id_en, Xol_lang_stub_.Id_de, Xol_lang_stub_.Id_pl, Xol_lang_stub_.Id_zh_hans, Xol_lang_stub_.Id_zh_hant); // add langs with translations first, so they alphabetize to top of list
@@ -61,7 +61,7 @@ class Options_list_lang_ {
}
untranslated.Sort_by(Xol_lang_stub_.Comparer_key);
KeyVal[] rv = new KeyVal[len];
Keyval[] rv = new Keyval[len];
int translated_max = translated.Count();
for (int i = 0; i < translated_max; i++)
rv[i] = new_itm((Xol_lang_stub)translated.Get_at(i));
@@ -70,10 +70,10 @@ class Options_list_lang_ {
rv[i] = new_itm((Xol_lang_stub)untranslated.Get_at(i - translated_max));
return rv;
}
private static KeyVal new_itm(Xol_lang_stub itm) {
private static Keyval new_itm(Xol_lang_stub itm) {
String key_str = String_.new_u8(itm.Key());
String name_str = String_.new_u8(itm.Canonical_name());
return KeyVal_.new_(key_str, name_str + " [" + key_str + "]");
return Keyval_.new_(key_str, name_str + " [" + key_str + "]");
}
private static void Add_itm_many(Ordered_hash translated, int... langs) {
int langs_len = langs.length;

View File

@@ -74,7 +74,6 @@ public class Xoav_app implements Xoa_app, GfoInvkAble {
public Bry_bfr_mkr Utl__bfr_mkr() {return Xoa_app_.Utl__bfr_mkr();}
public Json_parser Utl__json_parser() {return utl__json_parser;} private final Json_parser utl__json_parser = new Json_parser();
public boolean Bldr__running() {return bldr__running;} public void Bldr__running_(boolean v) {this.bldr__running = v;} private boolean bldr__running;
public Xop_amp_mgr Utl_amp_mgr() {return utl_amp_mgr;} private Xop_amp_mgr utl_amp_mgr = Xop_amp_mgr.Instance;
public Xol_case_mgr Utl_case_mgr() {return utl_case_mgr;} private Xol_case_mgr utl_case_mgr = Xol_case_mgr_.U8();
// public Gfo_url_encoder Utl_encoder_fsys() {return utl_encoder_fsys;} private Gfo_url_encoder utl_encoder_fsys = Gfo_url_encoder.New_fsys_lnx();

View File

@@ -50,10 +50,10 @@ xowa {
gui {
browser {
url {
focus();
exec_by_paste();
exec_new_tab_by_paste();
restore();
focus();
exec_by_paste();
exec_new_tab_by_paste();
restore();
exec();
}
search {
@@ -61,45 +61,45 @@ xowa {
exec();
}
tabs {
new_dflt__at_dflt__focus_y();
new_link__at_dflt__focus_n();
new_link__at_dflt__focus_y();
new_href__at_dflt__focus_y();
new_dupe__at_dflt__focus_y();
close_cur();
select_bwd();
select_fwd();
move_bwd();
move_fwd();
close_others();
close_to_bgn();
close_to_end();
close_undo();
pin_toggle();
select_by_idx_1();
select_by_idx_2();
select_by_idx_3();
select_by_idx_4();
select_by_idx_5();
select_by_idx_6();
select_by_idx_7();
select_by_idx_8();
new_dflt__at_dflt__focus_y();
new_link__at_dflt__focus_n();
new_link__at_dflt__focus_y();
new_href__at_dflt__focus_y();
new_dupe__at_dflt__focus_y();
close_cur();
select_bwd();
select_fwd();
move_bwd();
move_fwd();
close_others();
close_to_bgn();
close_to_end();
close_undo();
pin_toggle();
select_by_idx_1();
select_by_idx_2();
select_by_idx_3();
select_by_idx_4();
select_by_idx_5();
select_by_idx_6();
select_by_idx_7();
select_by_idx_8();
select_by_idx_9();
}
html {
focus();
selection_focus_toggle();
focus();
selection_focus_toggle();
load_tid; // [mem,url]
}
find {
show();
show_by_paste();
hide();
exec();
type();
find_bwd();
find_fwd();
case_toggle();
show();
show_by_paste();
hide();
exec();
type();
find_bwd();
find_fwd();
case_toggle();
wrap_toggle();
}
prog {
@@ -107,11 +107,11 @@ xowa {
show_short_link;
}
info {
focus();
clear();
launch();
warn_enabled;
note_enabled;
focus();
clear();
launch();
warn_enabled;
note_enabled;
}
prog_log {
show();
@@ -124,30 +124,30 @@ xowa {
}
page {
edit {
copy();
select_all();
save();
save_draft();
preview();
focus_edit_box();
dbg_tmpl();
dbg_html();
exec();
}
selection {
copy();
select_all();
save_file_as();
}
view {
mode_read();
mode_edit();
mode_html();
reload();
refresh();
print();
save_as();
}
copy();
select_all();
save();
save_draft();
preview();
focus_edit_box();
dbg_tmpl();
dbg_html();
exec();
}
selection {
copy();
select_all();
save_file_as();
}
view {
mode_read();
mode_edit();
mode_html();
reload();
refresh();
print();
save_as();
}
}
}
html {

View File

@@ -40,16 +40,17 @@ public class Xoapi_root implements GfoInvkAble {
html_api.Page().Toggle_mgr().Img_dir_(img_dir);
usr_api.Init_by_app(app);
}
public Xoapi_app App() {return app_api;} private final Xoapi_app app_api = new Xoapi_app();
public Xoapi_nav Nav() {return nav_api;} private final Xoapi_nav nav_api = new Xoapi_nav();
public Xoapi_gui Gui() {return gui_api;} private final Xoapi_gui gui_api = new Xoapi_gui();
public Xoapi_html Html() {return html_api;} private final Xoapi_html html_api = new Xoapi_html();
public Xoapi_bldr Bldr() {return bldr_api;} private final Xoapi_bldr bldr_api = new Xoapi_bldr();
public Xoapi_net Net() {return net_api;} private final Xoapi_net net_api = new Xoapi_net();
public Xoapi_usr Usr() {return usr_api;} private final Xoapi_usr usr_api = new Xoapi_usr();
public Xoapi_special Special() {return special_api;} private final Xoapi_special special_api = new Xoapi_special();
public Xoapi_xtns Xtns() {return xtns_api;} private final Xoapi_xtns xtns_api = new Xoapi_xtns();
public Xoapi_app_wikis Wikis() {return app_wikis;} private final Xoapi_app_wikis app_wikis = new Xoapi_app_wikis();
public Xoapi_addon Addon() {return addon_api;} private final Xoapi_addon addon_api = new Xoapi_addon();
public Xoapi_app App() {return app_api;} private final Xoapi_app app_api = new Xoapi_app();
public Xoapi_nav Nav() {return nav_api;} private final Xoapi_nav nav_api = new Xoapi_nav();
public Xoapi_gui Gui() {return gui_api;} private final Xoapi_gui gui_api = new Xoapi_gui();
public Xoapi_html Html() {return html_api;} private final Xoapi_html html_api = new Xoapi_html();
public Xoapi_bldr Bldr() {return bldr_api;} private final Xoapi_bldr bldr_api = new Xoapi_bldr();
public Xoapi_net Net() {return net_api;} private final Xoapi_net net_api = new Xoapi_net();
public Xoapi_usr Usr() {return usr_api;} private final Xoapi_usr usr_api = new Xoapi_usr();
public Xoapi_special Special() {return special_api;} private final Xoapi_special special_api = new Xoapi_special();
public Xoapi_xtns Xtns() {return xtns_api;} private final Xoapi_xtns xtns_api = new Xoapi_xtns();
public Xoapi_app_wikis Wikis() {return app_wikis;} private final Xoapi_app_wikis app_wikis = new Xoapi_app_wikis();
public String Test_str() {return test_str;} public void Test_str_(String v) {test_str = v;} private String test_str; // TEST
private void Exec(String key) {
Xog_cmd_itm cmd_itm = app.Gui_mgr().Cmd_mgr().Get_or_null(key);
@@ -58,6 +59,7 @@ public class Xoapi_root implements GfoInvkAble {
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_app)) return app_api;
else if (ctx.Match(k, Invk_addon)) return addon_api;
else if (ctx.Match(k, Invk_bldr)) return bldr_api;
else if (ctx.Match(k, Invk_nav)) return nav_api;
else if (ctx.Match(k, Invk_gui)) return gui_api;
@@ -74,7 +76,8 @@ public class Xoapi_root implements GfoInvkAble {
}
private static final String
Invk_exec = "exec"
, Invk_app = "app", Invk_bldr = "bldr", Invk_nav = "nav", Invk_gui = "gui", Invk_html = "html", Invk_net = "net", Invk_usr = "usr", Invk_special = "special", Invk_xtns = "xtns"
, Invk_app = "app", Invk_addon = "addon"
, Invk_bldr = "bldr", Invk_nav = "nav", Invk_gui = "gui", Invk_html = "html", Invk_net = "net", Invk_usr = "usr", Invk_special = "special", Invk_xtns = "xtns"
, Invk_test_str = "test_str", Invk_test_str_ = "test_str_"
, Invk_wikis = "wikis"
;

Some files were not shown because too many files have changed in this diff Show More