mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-24 14:57:44 +00:00
Merge branch 'feat/developer/kmc-convert' into feat/developer/kmc-convert-createSeperateUtil
This commit is contained in:
commit
59ed7152eb
70 changed files with 12353 additions and 4935 deletions
46
HISTORY.md
46
HISTORY.md
|
|
@ -1,5 +1,40 @@
|
|||
# Keyman Version History
|
||||
|
||||
## 19.0.202 alpha 2026-02-12
|
||||
|
||||
* fix(linux): check for existing file before trying to install (#15573)
|
||||
|
||||
## 19.0.201 alpha 2026-02-09
|
||||
|
||||
* fix(linux): include missing artifacts in source tarball (#15566)
|
||||
* chore(linux): use xz compression for source tarballs (#15568)
|
||||
|
||||
## 19.0.200 alpha 2026-02-06
|
||||
|
||||
* change(web): define, utilize cleaner Web test-resource import paths (#15564)
|
||||
* maint(mac): upgrade to Xcode 26.2 (#15484)
|
||||
|
||||
## 19.0.199 alpha 2026-02-05
|
||||
|
||||
* chore(deps): bump @isaacs/brace-expansion from 5.0.0 to 5.0.1 in /developer/src/server/src/win32/trayicon/addon-src (#15552)
|
||||
* fix(windows): unresponsive splash screen (#15269)
|
||||
* maint(common): Update langtags.json to 2026-02-03 release (v1.4) (#15459)
|
||||
* feat(android): Use current display language for keyboard search (#15510)
|
||||
* chore(linux): Update debian changelog (#15557)
|
||||
* chore(linux): update copyright year and standards version (#15559)
|
||||
|
||||
## 19.0.198 alpha 2026-02-04
|
||||
|
||||
* fix(core): handle backspace decomposition (#15488)
|
||||
* fix(core): normalization segment should end on NFC boundary, not NFD (#15506)
|
||||
|
||||
## 19.0.197 alpha 2026-02-02
|
||||
|
||||
* chore(deps): bump tar from 7.5.6 to 7.5.7 in /developer/src/server/src/win32/trayicon/addon-src (#15514)
|
||||
* chore(deps): bump fast-xml-parser from 5.2.2 to 5.3.4 (#15526)
|
||||
* fix(windows): handle symstore correctly from bash script (#15524)
|
||||
* chore(ios): Add fv_tlingityooxatangi to FirstVoices for iOS app (#15485)
|
||||
|
||||
## 19.0.196 alpha 2026-01-30
|
||||
|
||||
* chore(common): Update Crowdin strings for `de` (#15511)
|
||||
|
|
@ -1170,6 +1205,17 @@
|
|||
* refactor(windows): rename `TKeymanMutex.MutexOwned` to `TakeOwnership` and add `ReleaseOwnership` (#13168)
|
||||
* chore: increment to alpha 19.0 (#13187)
|
||||
|
||||
## 18.0.246 stable 2026-02-04
|
||||
|
||||
* cherrypick(common): Update FirstVoices versions in keyboards.csv (#15273)
|
||||
* docs(ios): Use /cdn/dev assets for Engine guides (#15274)
|
||||
* chore(linux): Update debian changelog (#15281)
|
||||
* maint(linux): remove EOL Ubuntu 25.04 Plucky (#15424)
|
||||
* docs(developer): update primerprep link (#15468)
|
||||
* chore(ios): Add fv_tlingityooxatangi to FirstVoices for iOS app (#15496)
|
||||
* fix(core): handle backspace decomposition (#15494)
|
||||
* fix(core): normalization segment should end on NFC boundary, not NFD (#15551)
|
||||
|
||||
## 18.0.245 stable 2025-12-03
|
||||
|
||||
* chore(windows): VS2022 patch for stable-18.0 (#15081)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
19.0.197
|
||||
19.0.203
|
||||
|
|
@ -11,6 +11,7 @@ import android.graphics.Bitmap;
|
|||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.LocaleList;
|
||||
import android.util.AndroidRuntimeException;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
|
@ -38,7 +39,7 @@ public class KMPBrowserActivity extends BaseActivity {
|
|||
private static final String TAG = "KMPBrowserActivity";
|
||||
|
||||
// URL for keyboard search web page presented to user when they add a keyboard in the app.
|
||||
private static final String KMP_SEARCH_KEYBOARDS_FORMATSTR = "https://%s/go/android/%s/download-keyboards%s";
|
||||
private static final String KMP_SEARCH_KEYBOARDS_FORMATSTR = "https://%s/go/android/%s/download-keyboards%s?lang=%s";
|
||||
private static final String KMP_SEARCH_KEYBOARDS_LANGUAGES = "/languages/%s";
|
||||
|
||||
// Patterns for determining if a link should be opened in external browser
|
||||
|
|
@ -163,13 +164,7 @@ public class KMPBrowserActivity extends BaseActivity {
|
|||
}
|
||||
});
|
||||
|
||||
// Tier determines the keyboard search host
|
||||
String host = KMPLink.getHost();
|
||||
// If language ID is provided, include it in the keyboard search
|
||||
String languageID = getIntent().getStringExtra("languageCode");
|
||||
String languageStr = (languageID != null) ? KMString.format(KMP_SEARCH_KEYBOARDS_LANGUAGES, languageID) : "";
|
||||
String appMajorVersion = KMManager.getMajorVersion();
|
||||
String kmpSearchUrl = KMString.format(KMP_SEARCH_KEYBOARDS_FORMATSTR, host, appMajorVersion, languageStr);
|
||||
String kmpSearchUrl = determineSearchUrl();
|
||||
webView.loadUrl(kmpSearchUrl);
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +173,8 @@ public class KMPBrowserActivity extends BaseActivity {
|
|||
super.onResume();
|
||||
|
||||
if (webView != null) {
|
||||
webView.reload();
|
||||
String kmpSearchUrl = determineSearchUrl();
|
||||
webView.loadUrl(kmpSearchUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,6 +217,32 @@ public class KMPBrowserActivity extends BaseActivity {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the keyman.com keyboard search URL while accounting for:
|
||||
* host (production or staging)
|
||||
* languageID - language ID to search for
|
||||
* display language - request search results to be displayed in this language
|
||||
* @return String
|
||||
*/
|
||||
private String determineSearchUrl() {
|
||||
// Tier determines the keyboard search host
|
||||
String host = KMPLink.getHost();
|
||||
|
||||
// If display language is provided, include it in the keyboard search. Otherwise fallback to default locale
|
||||
String fallbackLang = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) ?
|
||||
LocaleList.getDefault().get(0).toLanguageTag() : "en";
|
||||
Bundle bundle = getIntent().getExtras();
|
||||
String displayLang = (bundle != null) && bundle.containsKey("lang") ? bundle.getString("lang") : fallbackLang;
|
||||
|
||||
// If language ID is provided for keyboard search, include it in the keyboard search
|
||||
String languageID = getIntent().getStringExtra("languageCode");
|
||||
String languageStr = (languageID != null) ? KMString.format(KMP_SEARCH_KEYBOARDS_LANGUAGES, languageID) : "";
|
||||
|
||||
String appMajorVersion = KMManager.getMajorVersion();
|
||||
String kmpSearchUrl = KMString.format(KMP_SEARCH_KEYBOARDS_FORMATSTR, host, appMajorVersion, languageStr, displayLang);
|
||||
return kmpSearchUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a URL is a valid internal Keyman keyboard link
|
||||
* @param url String of the URL to parse
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ import java.util.HashMap;
|
|||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -24,6 +26,7 @@ import android.widget.SimpleAdapter;
|
|||
import android.widget.TextView;
|
||||
|
||||
import com.keyman.engine.BaseActivity;
|
||||
import com.keyman.engine.DisplayLanguages;
|
||||
import com.keyman.engine.KMManager;
|
||||
import com.keyman.engine.data.KeyboardController;
|
||||
import com.keyman.engine.util.MapCompat;
|
||||
|
|
@ -127,12 +130,19 @@ public class KeymanSettingsInstallActivity extends BaseActivity {
|
|||
HashMap<String, String> hashMap = (HashMap<String, String>) parent.getItemAtPosition(position);
|
||||
String itemTitle = MapCompat.getOrDefault(hashMap, titleKey, "");
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String languageTag = prefs.getString(DisplayLanguages.displayLanguageKey, "");
|
||||
// Install from keyman.com
|
||||
if (itemTitle.equals(getString(R.string.install_from_keyman_dot_com))) {
|
||||
if (KMManager.hasConnection(context)) {
|
||||
Intent i = new Intent(context, KMPBrowserActivity.class);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
if (languageTag != null && !languageTag.isEmpty()) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("lang", languageTag);
|
||||
i.putExtras(bundle);
|
||||
}
|
||||
context.startActivity(i);
|
||||
} else {
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@ import androidx.annotation.NonNull;
|
|||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.keyman.engine.BaseActivity;
|
||||
import com.keyman.engine.DisplayLanguages;
|
||||
import com.keyman.engine.KeyboardPickerActivity;
|
||||
import com.keyman.engine.KMManager;
|
||||
import com.keyman.engine.ModelPickerActivity;
|
||||
|
|
@ -201,11 +203,19 @@ public final class LanguageSettingsActivity extends BaseActivity {
|
|||
if (KMManager.hasConnection(context)){
|
||||
// Scenario 1: Connection to keyman.com catalog
|
||||
// Pass the BCP47 language code to the KMPBrowserActivity
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String languageTag = prefs.getString(DisplayLanguages.displayLanguageKey, "");
|
||||
|
||||
Intent i = new Intent(context, KMPBrowserActivity.class);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
i.putExtra("languageCode", lgCode);
|
||||
i.putExtra("languageName", lgName);
|
||||
if (languageTag != null && !languageTag.isEmpty()) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("lang", languageTag);
|
||||
i.putExtras(bundle);
|
||||
}
|
||||
context.startActivity(i);
|
||||
/*
|
||||
} else if (KeyboardPickerActivity.hasKeyboardFromPackage()) {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ bool km::core::actions_normalize(
|
|||
boundary prior to the intersection of the cached_context and the output.
|
||||
*/
|
||||
if(!output.empty()) {
|
||||
while(n > 0 && !km::core::util::has_nfd_boundary_before(output[0])) {
|
||||
while(n > 0 && !km::core::util::has_nfc_boundary_before(output[0])) {
|
||||
// The output may interact with the context further in normalization. We
|
||||
// need to copy characters back further until we reach a normalization
|
||||
// boundary.
|
||||
|
|
@ -133,6 +133,7 @@ bool km::core::actions_normalize(
|
|||
To adjust, we remove one codepoint at a time from the app_context until
|
||||
its normalized form matches the cached_context normalized form.
|
||||
*/
|
||||
std::u32string context_final = U"";
|
||||
|
||||
while(!app_context_string.empty()) {
|
||||
auto app_context_nfd = app_context_string;
|
||||
|
|
@ -141,7 +142,16 @@ bool km::core::actions_normalize(
|
|||
return false;
|
||||
}
|
||||
|
||||
if(app_context_nfd == cached_context_string) {
|
||||
/*
|
||||
We are working in NFD as we backtrack in the context, but input variable
|
||||
app_context_string is NFC. The last character of the context may be part
|
||||
of a composed character, so we need to track decomposition. For example,
|
||||
'tä' + BKSP should result in 'ta', but delete back 1 in app_context_string
|
||||
will give us 't', so we need to remember 'a', and add it back afterwards
|
||||
(see output_nfc variable).
|
||||
*/
|
||||
if(app_context_nfd == cached_context_string.substr(0, app_context_nfd.length())) {
|
||||
context_final = cached_context_string.substr(app_context_nfd.length());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +165,7 @@ bool km::core::actions_normalize(
|
|||
Normalize our output string
|
||||
*/
|
||||
|
||||
auto output_nfc = output;
|
||||
auto output_nfc = context_final + output;
|
||||
if(!km::core::util::normalize_nfc(output_nfc)) {
|
||||
DebugLog("nfc->normalize failed");
|
||||
return false;
|
||||
|
|
@ -197,6 +207,8 @@ bool km::core::actions_normalize(
|
|||
actions.output = new_output;
|
||||
actions.code_points_to_delete = nfu_to_delete;
|
||||
|
||||
// Outcome will be: <app_context><context_final><output>|
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -395,13 +395,18 @@ const char *Debug_ModifierName(KMX_UINT modifiers) {
|
|||
}
|
||||
|
||||
const char *Debug_VirtualKey(KMX_WORD vk) {
|
||||
if (!ShouldDebug()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return Debug_VirtualKey_Always(vk);
|
||||
}
|
||||
|
||||
const char *Debug_VirtualKey_Always(KMX_WORD vk) {
|
||||
#ifdef _MSC_VER
|
||||
__declspec(thread)
|
||||
#endif
|
||||
static char buf[256];
|
||||
if (!ShouldDebug()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (vk < 256) {
|
||||
snprintf(buf, 256, "['%s' 0x%x]", s_key_names[vk], vk);
|
||||
|
|
@ -411,7 +416,6 @@ const char *Debug_VirtualKey(KMX_WORD vk) {
|
|||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *Debug_UnicodeString(PKMX_WCHAR s, int x) {
|
||||
if (!ShouldDebug()) {
|
||||
return "";
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ extern const char *s_key_names[];
|
|||
|
||||
int DebugLog_1(const char *file, int line, const char *function, const char *fmt, ...);
|
||||
const char *Debug_VirtualKey(KMX_WORD vk);
|
||||
const char *Debug_VirtualKey_Always(KMX_WORD vk);
|
||||
/**
|
||||
* @param s PKMX_WCHAR to output
|
||||
* @param x temporary buffer (0 or 1) to write to
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ bool is_nfd(const std::u32string& str) {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool has_nfd_boundary_before(km_core_usv cp) {
|
||||
bool has_nfc_boundary_before(km_core_usv cp) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// it's a negative table. entries in the table mean returning false. non-entries return true.
|
||||
for (auto i=0;i<(km_noBoundaryBefore_entries*2);i+=2) {
|
||||
|
|
@ -221,9 +221,9 @@ bool has_nfd_boundary_before(km_core_usv cp) {
|
|||
return true; // fallthrough
|
||||
#else
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
auto nfd = getNFD(status);
|
||||
if (nfd == nullptr) return false;
|
||||
return nfd->hasBoundaryBefore(cp);
|
||||
auto nfc = getNFC(status);
|
||||
if (nfc == nullptr) return false;
|
||||
return nfc->hasBoundaryBefore(cp);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ bool is_nfd(const std::u16string& str);
|
|||
bool is_nfd(const std::u32string& str);
|
||||
|
||||
/** @return true if cp can interacts with prior chars */
|
||||
bool has_nfd_boundary_before(km_core_usv cp);
|
||||
bool has_nfc_boundary_before(km_core_usv cp);
|
||||
|
||||
/** convenience function, caller owns storage */
|
||||
km_core_usv *string_to_usv(const std::u32string& src);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
|
||||
int
|
||||
write_nfd_table() {
|
||||
write_nfc_table() {
|
||||
#ifndef __EMSCRIPTEN__
|
||||
std::cerr << "Note: This is unusual - this generator is usually only run under emscripten!" << std::endl;
|
||||
#endif
|
||||
|
|
@ -49,13 +49,13 @@ write_nfd_table() {
|
|||
std::cout << std::endl;
|
||||
// we're going to need an NFD normalizer
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
const icu::Normalizer2 *nfd = icu::Normalizer2::getNFDInstance(status);
|
||||
const icu::Normalizer2 *nfc = icu::Normalizer2::getNFCInstance(status);
|
||||
assert(U_SUCCESS(status));
|
||||
|
||||
// collect the raw list of chars that do NOT have a boundary before them.
|
||||
std::vector<km_core_usv> noBoundary;
|
||||
for (km_core_usv ch = 0; ch < km::core::kmx::Uni_MAX_CODEPOINT; ch++) {
|
||||
bool bb = nfd->hasBoundaryBefore(ch);
|
||||
bool bb = nfc->hasBoundaryBefore(ch);
|
||||
assert(!(ch == 0 && !bb)); // assert that we can use U+0000 as a terminator
|
||||
if (bb) continue; //only emit nonboundary
|
||||
noBoundary.push_back(ch);
|
||||
|
|
@ -102,6 +102,6 @@ write_nfd_table() {
|
|||
|
||||
int
|
||||
main(int /*argc*/, const char * /*argv*/[]) {
|
||||
write_nfd_table();
|
||||
write_nfc_table();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -311,6 +311,17 @@ void run_actions_normalize_tests() {
|
|||
/* app_context: */ u"abcệ"
|
||||
);
|
||||
|
||||
test_actions_normalize(
|
||||
"One backspace to delete last NFD character (#15487)",
|
||||
/* app context pre transform: */ u"abcê", // NFC
|
||||
/* cached context post transform: */ u"abce",
|
||||
/* cached context post transform: */ nullptr,
|
||||
/* action del, output: */ 1, U"", // NFD input; delete 1: \u0302
|
||||
// ---- results ----
|
||||
/* action del, output: */ 1, U"e", // NFC output; delete 1: e
|
||||
/* app_context: */ u"abce"
|
||||
);
|
||||
|
||||
test_actions_normalize(
|
||||
"One backspace for NFD converts into one char in NFC (ê) and recombine",
|
||||
/* app context pre transform: */ u"abcê",
|
||||
|
|
@ -347,6 +358,18 @@ void run_actions_normalize_tests() {
|
|||
/* app_context: */ u"\u0323\u0300\u0302"
|
||||
);
|
||||
|
||||
// #15505 - normalization of Bengali characters
|
||||
test_actions_normalize(
|
||||
"Bengali normalization of U+09C7 U+09D7 -> U+09CC",
|
||||
/* app context pre transform: */ u"\u0995\u09C7",
|
||||
/* cached context post transform: */ u"\u0995\u09C7\u09D7",
|
||||
/* cached context post transform: */ nullptr,
|
||||
/* action del, output: */ 0, U"\u09D7",
|
||||
// ---- results ----
|
||||
/* action del, output: */ 1, U"\u09CC",
|
||||
/* app_context: */ u"\u0995\u09CC"
|
||||
);
|
||||
|
||||
// Modifies the base as well as diacritic
|
||||
|
||||
test_actions_normalize(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
Note that the 'expected' lines are cumulative unless there's a reset event.
|
||||
|
||||
@@keys: [K_A][K_B][K_SLASH][K_BKSP]
|
||||
@@expected: ab
|
||||
Comment: bkspace should delete just the U+0301
|
||||
|
||||
@@keys: [K_C][K_E][K_SLASH][K_BKSP]
|
||||
@@expected: abce
|
||||
Comment: #15487: bksp will delete just acute (even though it will have combined to NFC, internally we do NFD bksp)
|
||||
|
||||
TODO: this seems to be working NFD on app context side also, do we need to set a flag? this may break other tests so care is needed
|
||||
|
||||
-->
|
||||
|
||||
<keyboard3 xmlns="https://schemas.unicode.org/cldr/45/keyboard3" locale="en" conformsTo="45">
|
||||
<info author="Marc Durdin" name="Test BKSP"/>
|
||||
<version number="1.0.0"/>
|
||||
<keys>
|
||||
<import base="cldr" path="45/keys-Zyyy-punctuation.xml"/>
|
||||
<import base="cldr" path="45/keys-Zyyy-currency.xml"/>
|
||||
<key id="acute" output="\u{0301}"/>
|
||||
</keys>
|
||||
<layers formId="us">
|
||||
<layer modifiers="none">
|
||||
<row keys="grave 1 2 3 4 5 6 7 8 9 0 hyphen equal"/>
|
||||
<row keys="q w e r t y u i o p open-square close-square backslash"/>
|
||||
<row keys="a s d f g h j k l semi-colon apos"/>
|
||||
<row keys="z x c v b n m comma period acute"/>
|
||||
<row keys="space"/>
|
||||
</layer>
|
||||
<layer modifiers="shift">
|
||||
<row keys="tilde bang at hash dollar percent caret amp asterisk open-paren close-paren underscore plus"/>
|
||||
<row keys="Q W E R T Y U I O P open-curly close-curly pipe"/>
|
||||
<row keys="A S D F G H J K L colon double-quote"/>
|
||||
<row keys="Z X C V B N M open-angle close-angle question"/>
|
||||
<row keys="space"/>
|
||||
</layer>
|
||||
</layers>
|
||||
</keyboard3>
|
||||
|
|
@ -30,6 +30,7 @@ tests_without_testdata = [
|
|||
'k_100_keytest',
|
||||
'k_101_keytest',
|
||||
'k_102_keytest',
|
||||
'k_213_backspace_decomposition',
|
||||
]
|
||||
|
||||
# These tests have a *-test.xml file as well.
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
|
||||
namespace {
|
||||
|
||||
void print_context(std::u16string &text_store, km_core_state *&test_state, std::vector<km_core_context_item> &test_context);
|
||||
|
||||
bool g_beep_found = false;
|
||||
|
||||
km_core_option_item test_env_opts[] =
|
||||
|
|
@ -82,13 +84,15 @@ apply_action(
|
|||
std::vector<km_core_context_item> &context,
|
||||
km::tests::LdmlTestSource &test_source,
|
||||
std::vector<km_core_context_item> &test_context) {
|
||||
|
||||
// print_context(text_store, test_state, test_context);
|
||||
switch (act.type) {
|
||||
case KM_CORE_IT_END:
|
||||
test_assert(false);
|
||||
break;
|
||||
case KM_CORE_IT_ALERT:
|
||||
g_beep_found = true;
|
||||
// std::cout << "beep" << std::endl;
|
||||
std::cout << " + beep" << std::endl;
|
||||
break;
|
||||
case KM_CORE_IT_CHAR:
|
||||
context.push_back(km_core_context_item{
|
||||
|
|
@ -104,10 +108,10 @@ apply_action(
|
|||
text_store.push_back(buf.ch[i]);
|
||||
}
|
||||
}
|
||||
// std::cout << "char(" << act.character << ") size=" << cp->size() << std::endl;
|
||||
std::cout << " + char(" << act.character << ")" << std::endl;
|
||||
break;
|
||||
case KM_CORE_IT_MARKER:
|
||||
// std::cout << "deadkey(" << act.marker << ")" << std::endl;
|
||||
std::cout << " + deadkey(" << act.marker << ")" << std::endl;
|
||||
context.push_back(km_core_context_item{
|
||||
KM_CORE_CT_MARKER,
|
||||
{
|
||||
|
|
@ -117,6 +121,8 @@ apply_action(
|
|||
break;
|
||||
case KM_CORE_IT_BACK:
|
||||
{
|
||||
std::cout << " + back(" << act.backspace.expected_type << ")" << std::endl;
|
||||
|
||||
// single char removed in context
|
||||
km_core_usv ch = 0;
|
||||
bool matched_text = false;
|
||||
|
|
@ -167,10 +173,11 @@ apply_action(
|
|||
}
|
||||
break;
|
||||
case KM_CORE_IT_PERSIST_OPT:
|
||||
std::cout << " + TODO-LDML: persist_opt()" << std::endl;
|
||||
break;
|
||||
case KM_CORE_IT_INVALIDATE_CONTEXT:
|
||||
{
|
||||
std::cout << "action: context invalidated (markers cleared)" << std::endl;
|
||||
std::cout << " + context invalidated (markers cleared)" << std::endl;
|
||||
// TODO-LDML: We need the context for tests. So we will simulate recreating
|
||||
// the context from the context string.
|
||||
km_core_context_item* new_context_items = nullptr;
|
||||
|
|
@ -186,11 +193,11 @@ apply_action(
|
|||
}
|
||||
break;
|
||||
case KM_CORE_IT_EMIT_KEYSTROKE:
|
||||
std::cout << "action: emit keystroke" << std::endl;
|
||||
std::cout << " + emit keystroke" << std::endl;
|
||||
// TODO-LDML: For now, this is a no-op. We could handle enter, etc.
|
||||
break;
|
||||
case KM_CORE_IT_CAPSLOCK:
|
||||
std::cout << "action: capsLock " << act.capsLock << std::endl;
|
||||
std::cout << " + capsLock " << act.capsLock << std::endl;
|
||||
test_source.set_caps_lock_on(act.capsLock);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -199,11 +206,46 @@ apply_action(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* verify the current context
|
||||
*/
|
||||
|
||||
void
|
||||
verify_context(std::u16string &text_store, km_core_state *&test_state, std::vector<km_core_context_item> &test_context) {
|
||||
apply_actions(
|
||||
km_core_state *test_state,
|
||||
km_core_actions const *actions,
|
||||
std::u16string &text_store,
|
||||
std::vector<km_core_context_item> &context,
|
||||
km::tests::LdmlTestSource &test_source,
|
||||
std::vector<km_core_context_item> &test_context
|
||||
) {
|
||||
|
||||
if(actions->do_alert) {
|
||||
apply_action(test_state, {KM_CORE_IT_ALERT}, text_store, context, test_source, test_context);
|
||||
}
|
||||
|
||||
if(actions->code_points_to_delete) {
|
||||
for(unsigned int i = 0; i < actions->code_points_to_delete; i++) {
|
||||
km_core_action_item act = {KM_CORE_IT_BACK};
|
||||
act.backspace = {KM_CORE_BT_CHAR, 0};
|
||||
apply_action(test_state, act, text_store, context, test_source, test_context);
|
||||
}
|
||||
}
|
||||
|
||||
if(actions->output) {
|
||||
for(auto ch = actions->output; *ch; ch++) {
|
||||
km_core_action_item act = {KM_CORE_IT_CHAR};
|
||||
act.character = *ch;
|
||||
apply_action(test_state, act, text_store, context, test_source, test_context);
|
||||
}
|
||||
}
|
||||
|
||||
if(actions->emit_keystroke) {
|
||||
apply_action(test_state, {KM_CORE_IT_EMIT_KEYSTROKE}, text_store, context, test_source, test_context);
|
||||
}
|
||||
|
||||
// TODO-LDML: other action types - persist, caps lock
|
||||
}
|
||||
|
||||
void
|
||||
print_context(std::u16string &text_store, km_core_state *&test_state, std::vector<km_core_context_item> &test_context) {
|
||||
// Compare context and text store at each step - should be identical
|
||||
size_t n = 0;
|
||||
km_core_context_item *citems = nullptr;
|
||||
|
|
@ -225,8 +267,18 @@ verify_context(std::u16string &text_store, km_core_state *&test_state, std::vect
|
|||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << "context : " << string_to_hex(buf) << " [" << buf << "]" << std::endl;
|
||||
std::cout << "testcontext ";
|
||||
std::cout << "context : " << string_to_hex(buf) << " [" << buf << "]" << std::endl;
|
||||
|
||||
delete[] buf;
|
||||
|
||||
km_core_context_item *citems_app = nullptr;
|
||||
try_status(km_core_context_get(km_core_state_app_context(test_state), &citems_app));
|
||||
try_status(context_items_to_utf16(citems_app, nullptr, &n));
|
||||
buf = new km_core_cu[n];
|
||||
try_status(context_items_to_utf16(citems_app, buf, &n));
|
||||
std::cout << "app context : " << string_to_hex(buf) << " [" << buf << "]" << std::endl;
|
||||
|
||||
std::cout << "test_context : ";
|
||||
std::cout.fill('0');
|
||||
for (auto i = test_context.begin(); i < test_context.end(); i++) {
|
||||
switch (i->type) {
|
||||
|
|
@ -241,29 +293,60 @@ verify_context(std::u16string &text_store, km_core_state *&test_state, std::vect
|
|||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
km_core_context_items_dispose(citems);
|
||||
km_core_context_items_dispose(citems_app);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
// Verify that both our local test_context and the core's test_state.context have
|
||||
// not diverged
|
||||
auto ci = citems;
|
||||
for (auto test_ci = test_context.begin();; ci++, test_ci++) {
|
||||
// skip over markers, they won't be in test_context
|
||||
while (ci->type == KM_CORE_CT_MARKER) {
|
||||
ci++;
|
||||
/**
|
||||
* verify the current context
|
||||
*/
|
||||
void
|
||||
verify_context(std::u16string &text_store, km_core_state *&test_state, std::vector<km_core_context_item> &test_context, bool fully_normalized_mode, bool normalization_enabled) {
|
||||
// Compare context and text store at each step - should be identical
|
||||
print_context(text_store, test_state, test_context);
|
||||
|
||||
size_t n = 0;
|
||||
km_core_context_item *citems = nullptr;
|
||||
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(context_items_to_utf16(citems, nullptr, &n));
|
||||
km_core_cu *buf = new km_core_cu[n];
|
||||
try_status(context_items_to_utf16(citems, buf, &n));
|
||||
std::u16string buf_final(buf);
|
||||
|
||||
if(fully_normalized_mode) {
|
||||
if(normalization_enabled) {
|
||||
test_assert(km::core::util::normalize_nfc(buf_final));
|
||||
}
|
||||
// exit if BOTH are at end.
|
||||
if (ci->type == KM_CORE_CT_END && test_ci == test_context.end()) {
|
||||
break; // success
|
||||
// note: we don't compare test_context with citems because they have different
|
||||
// normalization forms in fully_normalized_mode
|
||||
} else {
|
||||
// Verify that both our local test_context and the core's test_state.context have
|
||||
// not diverged
|
||||
auto ci = citems;
|
||||
for (auto test_ci = test_context.begin();; ci++, test_ci++) {
|
||||
// skip over markers, they won't be in test_context
|
||||
while (ci->type == KM_CORE_CT_MARKER) {
|
||||
ci++;
|
||||
}
|
||||
// exit if BOTH are at end.
|
||||
if (ci->type == KM_CORE_CT_END && test_ci == test_context.end()) {
|
||||
break; // success
|
||||
}
|
||||
// fail if only ONE is at end
|
||||
test_assert(ci->type != KM_CORE_CT_END && test_ci != test_context.end());
|
||||
// fail if type and marker don't match.
|
||||
test_assert(test_ci->type == ci->type && test_ci->marker == ci->marker);
|
||||
}
|
||||
// fail if only ONE is at end
|
||||
test_assert(ci->type != KM_CORE_CT_END && test_ci != test_context.end());
|
||||
// fail if type and marker don't match.
|
||||
test_assert(test_ci->type == ci->type && test_ci->marker == ci->marker);
|
||||
}
|
||||
|
||||
km_core_context_items_dispose(citems);
|
||||
if (text_store != buf) {
|
||||
|
||||
if (text_store != buf_final) {
|
||||
std::cerr << "text store has diverged from buf" << std::endl;
|
||||
std::cerr << "text store: " << string_to_hex(text_store) << " [" << text_store << "]" << std::endl;
|
||||
std::cerr << "buf_final : " << string_to_hex(buf_final) << " [" << buf << "]" << std::endl;
|
||||
std::cerr << "buf : " << string_to_hex(buf) << " [" << buf << "]" << std::endl;
|
||||
test_assert(false);
|
||||
}
|
||||
delete[] buf;
|
||||
|
|
@ -327,7 +410,7 @@ verify_key_list(const km_core_keyboard_key *actual_list, const std::u16string &e
|
|||
}
|
||||
|
||||
int
|
||||
run_test(const km::core::path &source, const km::core::path &compiled, km::tests::LdmlTestSource& test_source) {
|
||||
run_test(const km::core::path &source, const km::core::path &compiled, km::tests::LdmlTestSource& test_source, bool fully_normalized_mode) {
|
||||
km_core_keyboard * test_kb = nullptr;
|
||||
km_core_state * test_state = nullptr;
|
||||
|
||||
|
|
@ -341,18 +424,28 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
|
|||
}
|
||||
|
||||
// setup normalization status
|
||||
const bool normalization_disabled = !test_kb->supports_normalization();
|
||||
test_source.set_normalization_disabled(normalization_disabled);
|
||||
const bool normalization_enabled = test_kb->supports_normalization();
|
||||
test_source.set_normalization_disabled(!normalization_enabled);
|
||||
std::wcout
|
||||
<< console_color::fg(console_color::BLUE) << "* normalization enabled = " << normalization_enabled
|
||||
<< console_color::reset() << std::endl << std::endl;
|
||||
|
||||
// Setup state, environment
|
||||
try_status(km_core_state_create(test_kb, test_env_opts, &test_state));
|
||||
|
||||
g_beep_found = false;
|
||||
|
||||
std::vector<km_core_context_item> test_context;
|
||||
|
||||
km_core_context_item *citems = nullptr;
|
||||
// setup test_context
|
||||
try_status(context_items_from_utf16(test_source.get_context().c_str(), &citems));
|
||||
try_status(km_core_context_set(km_core_state_context(test_state), citems));
|
||||
|
||||
if(fully_normalized_mode) {
|
||||
km_core_state_context_set_if_needed(test_state, test_source.get_context().c_str());
|
||||
} else {
|
||||
try_status(km_core_context_set(km_core_state_context(test_state), citems));
|
||||
}
|
||||
|
||||
// Make a copy of the setup context for the test
|
||||
copy_context_items_to_vector(citems, test_context);
|
||||
|
|
@ -364,7 +457,7 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
|
|||
km::tests::ldml_action action;
|
||||
|
||||
// verify at beginning
|
||||
verify_context(text_store, test_state, test_context);
|
||||
verify_context(text_store, test_state, test_context, fully_normalized_mode, normalization_enabled);
|
||||
|
||||
int errorLine = 0; // nonzero if err.
|
||||
|
||||
|
|
@ -377,8 +470,8 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
|
|||
break;
|
||||
case km::tests::LDML_ACTION_KEY_EVENT: {
|
||||
auto &p = action.k;
|
||||
std::cout << "- key action: " << km::core::kmx::Debug_VirtualKey(p.vk) << "/modifier "
|
||||
<< km::core::kmx::Debug_ModifierName(p.modifier_state) << " 0x" << p.modifier_state << std::dec << std::endl;
|
||||
std::cout << std::endl << "- key action: " << km::core::kmx::Debug_VirtualKey_Always(p.vk) << " modifier: ["
|
||||
<< km::core::kmx::Debug_ModifierName(p.modifier_state) << " 0x" << p.modifier_state << std::dec << "]" << std::endl;
|
||||
// Because a normal system tracks caps lock state itself,
|
||||
// we mimic that in the tests. We assume caps lock state is
|
||||
// updated on key_down before the processor receives the
|
||||
|
|
@ -388,6 +481,7 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
|
|||
}
|
||||
|
||||
for (auto key_down = 1; key_down >= 0; key_down--) {
|
||||
std::cout << " - key_down = " << key_down << std::endl;
|
||||
// expected error only applies to key down
|
||||
try_status(km_core_process_event(
|
||||
test_state, p.vk, p.modifier_state | test_source.caps_lock_state(), key_down,
|
||||
|
|
@ -398,11 +492,17 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
|
|||
test_context.clear();
|
||||
text_store.clear();
|
||||
}
|
||||
for (auto act = km_core_state_action_items(test_state, nullptr); act->type != KM_CORE_IT_END; act++) {
|
||||
apply_action(test_state, *act, text_store, test_context, test_source, test_context);
|
||||
|
||||
if(fully_normalized_mode) {
|
||||
auto actions = km_core_state_get_actions(test_state);
|
||||
apply_actions(test_state, actions, text_store, test_context, test_source, test_context);
|
||||
} else {
|
||||
for (auto act = km_core_state_action_items(test_state, nullptr); act->type != KM_CORE_IT_END; act++) {
|
||||
apply_action(test_state, *act, text_store, test_context, test_source, test_context);
|
||||
}
|
||||
}
|
||||
verify_context(text_store, test_state, test_context, fully_normalized_mode, normalization_enabled);
|
||||
}
|
||||
verify_context(text_store, test_state, test_context);
|
||||
} break;
|
||||
case km::tests::LDML_ACTION_EMIT_STRING: {
|
||||
std::cout << "- string emit action: " << action.string << std::endl;
|
||||
|
|
@ -418,13 +518,17 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
|
|||
}
|
||||
km_core_context_items_dispose(nitems);
|
||||
|
||||
verify_context(text_store, test_state, test_context);
|
||||
verify_context(text_store, test_state, test_context, fully_normalized_mode, normalization_enabled);
|
||||
} break;
|
||||
case km::tests::LDML_ACTION_CHECK_EXPECTED: {
|
||||
if (!normalization_disabled) {
|
||||
test_assert(km::core::util::normalize_nfd(action.string)); // TODO-LDML: should be NFC
|
||||
if (normalization_enabled) {
|
||||
if (!fully_normalized_mode) {
|
||||
test_assert(km::core::util::normalize_nfd(action.string));
|
||||
} else {
|
||||
test_assert(km::core::util::normalize_nfc(action.string));
|
||||
}
|
||||
}
|
||||
std::cout << "- check expected" << std::endl;
|
||||
std::cout << std::endl << "# check expected" << std::endl;
|
||||
std::cout << "expected : " << string_to_hex(action.string) << " [" << action.string << "]" << std::endl;
|
||||
std::cout << "text store: " << string_to_hex(text_store) << " [" << text_store << "]" << std::endl;
|
||||
// Compare internal context with expected result
|
||||
|
|
@ -433,7 +537,7 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
|
|||
}
|
||||
} break;
|
||||
case km::tests::LDML_ACTION_CHECK_KEYLIST: {
|
||||
std::cout << "- checking keylist" << std::endl;
|
||||
std::cout << std::endl << "# checking keylist" << std::endl;
|
||||
// get keylist from kbd
|
||||
const km_core_keyboard_key* actual_list = test_kb->get_key_list();
|
||||
if (!verify_key_list(actual_list, action.string, test_source)) {
|
||||
|
|
@ -462,7 +566,7 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
|
|||
|
||||
if (errorLine != 0) {
|
||||
// re-verify at end (if there wasn't already a failure)
|
||||
verify_context(text_store, test_state, test_context);
|
||||
verify_context(text_store, test_state, test_context, fully_normalized_mode, normalization_enabled);
|
||||
}
|
||||
|
||||
// cleanup
|
||||
|
|
@ -476,15 +580,19 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
|
|||
return __LINE__;
|
||||
}
|
||||
|
||||
if(errorLine != 0) {
|
||||
std::wcout << console_color::fg(console_color::BRIGHT_RED) << "- FAIL - error on line " << errorLine << console_color::reset() << std::endl;
|
||||
}
|
||||
|
||||
return errorLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all tests for this keyboard
|
||||
*/
|
||||
int run_all_tests(const km::core::path &source, const km::core::path &compiled, const std::string &filter) {
|
||||
std::wcout << console_color::fg(console_color::BLUE) << "source file = " << source << std::endl
|
||||
<< "compiled file = " << compiled << console_color::reset() << std::endl;
|
||||
int run_all_tests(const km::core::path &source, const km::core::path &compiled, const std::string &filter, bool fully_normalized_mode) {
|
||||
std::wcout << console_color::fg(console_color::BLUE) << "* source file = " << source << std::endl
|
||||
<< "* compiled file = " << compiled << console_color::reset() << std::endl;
|
||||
if(!filter.empty()) {
|
||||
std::wcout << "Running only tests matching (substring search): " << filter.c_str() << std::endl;
|
||||
}
|
||||
|
|
@ -497,14 +605,14 @@ int run_all_tests(const km::core::path &source, const km::core::path &compiled,
|
|||
|
||||
if (!filter.empty()) {
|
||||
// Always skip the embedded test if there's a filter.
|
||||
std::wcout << console_color::fg(console_color::YELLOW) << "SKIP: " << source.name() << " (embedded)" << console_color::reset()
|
||||
std::wcout << console_color::fg(console_color::YELLOW) << "* SKIP: " << source.name() << " (embedded)" << console_color::reset()
|
||||
<< std::endl;
|
||||
embedded_result = 0; // no error
|
||||
} else if (embedded_result == 0) {
|
||||
// embedded loaded OK, try it
|
||||
std::wcout << console_color::fg(console_color::BLUE) << console_color::bold() << "TEST: " << source.name() << " (embedded)"
|
||||
std::wcout << console_color::fg(console_color::BLUE) << console_color::bold() << "* TEST: " << source.name() << " (embedded)"
|
||||
<< console_color::reset() << std::endl;
|
||||
embedded_result = run_test(source, compiled, embedded_test_source);
|
||||
embedded_result = run_test(source, compiled, embedded_test_source, fully_normalized_mode);
|
||||
if (embedded_result != 0) {
|
||||
failures.push_back("in-XML (@@ comment) embedded test failed");
|
||||
}
|
||||
|
|
@ -533,7 +641,7 @@ int run_all_tests(const km::core::path &source, const km::core::path &compiled,
|
|||
continue;
|
||||
}
|
||||
std::wcout << console_color::fg(console_color::BLUE) << "TEST: " << json_path.stem().c_str() << "/" << console_color::bold() << n.first.c_str() << console_color::reset() << std::endl;
|
||||
int sub_test = run_test(source, compiled, *n.second);
|
||||
int sub_test = run_test(source, compiled, *n.second, fully_normalized_mode);
|
||||
if (sub_test != 0) {
|
||||
std::wcout << console_color::fg(console_color::BRIGHT_RED) << "FAIL: " << json_path.stem() << "/" << console_color::bold() << n.first.c_str()
|
||||
<< console_color::reset() << std::endl;
|
||||
|
|
@ -632,7 +740,15 @@ int main(int argc, char *argv[]) {
|
|||
filter = argv[first_arg++];
|
||||
}
|
||||
|
||||
int rc = run_all_tests(ldml_file, kmx_file, filter);
|
||||
std::cout << "1. Running tests in NFD mode" << std::endl;
|
||||
int rc = run_all_tests(ldml_file, kmx_file, filter, false);
|
||||
if (rc != EXIT_SUCCESS) {
|
||||
std::wcerr << console_color::fg(console_color::BRIGHT_RED) << "FAILED" << console_color::reset() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::cout << std::endl << "2. Running tests in fully normalized mode" << std::endl;
|
||||
rc = run_all_tests(ldml_file, kmx_file, filter, true);
|
||||
if (rc != EXIT_SUCCESS) {
|
||||
std::wcerr << console_color::fg(console_color::BRIGHT_RED) << "FAILED" << console_color::reset() << std::endl;
|
||||
rc = EXIT_FAILURE;
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ LdmlTestSource::get_modifier(std::string const &m) {
|
|||
|
||||
std::string key_event::dump() const {
|
||||
std::stringstream f;
|
||||
f << "Key: {" << km::core::kmx::Debug_VirtualKey(vk) << ", " << km::core::kmx::Debug_ModifierName(modifier_state) << "}";
|
||||
f << "Key: {" << km::core::kmx::Debug_VirtualKey_Always(vk) << ", " << km::core::kmx::Debug_ModifierName(modifier_state) << "}";
|
||||
return f.str();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,9 +187,20 @@ const std::string &block_unicode_ver) {
|
|||
inline const char *boolstr(bool b) {
|
||||
return b?"T":"f";
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_has_boundary_before() {
|
||||
std::cout << "= " << __FUNCTION__ << std::endl;
|
||||
|
||||
// Latin - #15505
|
||||
test_assert(km::core::util::has_nfc_boundary_before(0x0065));
|
||||
test_assert(!km::core::util::has_nfc_boundary_before(0x0301));
|
||||
|
||||
// Bengali - #15505
|
||||
test_assert(km::core::util::has_nfc_boundary_before(0x0995));
|
||||
test_assert(!km::core::util::has_nfc_boundary_before(0x09d7));
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
std::cout << "I see we are on Emscripten / wasm! Now we will do some additional tests." << std::endl;
|
||||
std::string icu4c_unicode(U_UNICODE_VERSION), header_unicode(KM_HASBOUNDARYBEFORE_UNICODE_VERSION),
|
||||
icu4c_icu(U_ICU_VERSION), header_icu(KM_HASBOUNDARYBEFORE_ICU_VERSION);
|
||||
|
|
@ -198,26 +209,26 @@ void test_has_boundary_before() {
|
|||
assert_basic_equal(icu4c_unicode, header_unicode);
|
||||
assert_basic_equal(icu4c_icu, header_icu);
|
||||
|
||||
std::cout << std::endl << "Now, let's make sure has_nfd_boundary_before() matches ICU." << std::endl;
|
||||
std::cout << std::endl << "Now, let's make sure has_nfc_boundary_before() matches ICU." << std::endl;
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
const icu::Normalizer2 *nfd = icu::Normalizer2::getNFDInstance(status);
|
||||
const icu::Normalizer2 *nfc = icu::Normalizer2::getNFCInstance(status);
|
||||
UASSERT_SUCCESS(status);
|
||||
|
||||
// now, test that hasBoundaryBefore is the same
|
||||
for (km_core_usv cp = 0; cp < km::core::kmx::Uni_MAX_CODEPOINT; cp++) {
|
||||
auto km_hbb = km::core::util::has_nfd_boundary_before(cp);
|
||||
auto icu_hbb = nfd->hasBoundaryBefore(cp);
|
||||
auto km_hbb = km::core::util::has_nfc_boundary_before(cp);
|
||||
auto icu_hbb = nfc->hasBoundaryBefore(cp);
|
||||
|
||||
if (km_hbb != icu_hbb) {
|
||||
std::cerr << "Error: util_normalize_table.h said " << boolstr(km_hbb) << " but ICU said " << boolstr(icu_hbb) << " for "
|
||||
<< "has_nfd_boundary_before(0x" << std::hex << cp << std::dec << ")" << std::endl;
|
||||
<< "has_nfc_boundary_before(0x" << std::hex << cp << std::dec << ")" << std::endl;
|
||||
}
|
||||
test_assert(km_hbb == icu_hbb);
|
||||
}
|
||||
#endif
|
||||
std::cout << "All OK!" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
int test_all(const char *jsonpath, const char *packagepath, const char *blockspath) {
|
||||
std::cout << "= " << __FUNCTION__ << std::endl;
|
||||
|
|
@ -234,9 +245,7 @@ int test_all(const char *jsonpath, const char *packagepath, const char *blockspa
|
|||
|
||||
test_unicode_versions(versions, package, block_unicode_ver);
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
test_has_boundary_before();
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"dependencies": {
|
||||
"@keymanapp/common-types": "*",
|
||||
"eventemitter3": "^5.0.0",
|
||||
"fast-xml-parser": "^5.2.2",
|
||||
"fast-xml-parser": "^5.3.4",
|
||||
"path-browserify": "^1.0.1",
|
||||
"restructure": "^3.0.1",
|
||||
"sax": ">=0.6.0",
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ export { LDMLKeyboardTestDataXMLSourceFile } from './types/ldml-keyboard/ldml-ke
|
|||
export { LDMLKeyboardXMLSourceFileReader, LDMLKeyboardXMLSourceFileReaderOptions } from './types/ldml-keyboard/ldml-keyboard-xml-reader.js';
|
||||
|
||||
export * as Keylayout from './types/keylayout/keylayout-xml.js';
|
||||
export { KeylayoutXMLSourceFile } from './types/keylayout/keylayout-xml.js';
|
||||
|
||||
export {
|
||||
CompilerAsyncCallbacks,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Keyman is 2025 copyright (C) SIL International. MIT License.
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Created by S. Schmitt on 2025-06-12
|
||||
*
|
||||
|
|
@ -14,6 +14,7 @@ export interface KeylayoutXMLSourceFile {
|
|||
*/
|
||||
keyboard: KL_keyboard;
|
||||
};
|
||||
|
||||
export interface KL_keyboard {
|
||||
group?: string;
|
||||
id?: string;
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ const PARSER_OPTIONS: KeymanXMLParserOptionsBag = {
|
|||
preserveOrder: true, // Gives us a 'special' format
|
||||
},
|
||||
'keylayout': {
|
||||
attributeNamePrefix: '@_', // avoid @_
|
||||
attributeNamePrefix: '@__',
|
||||
htmlEntities: true,
|
||||
ignoreAttributes: false, // We'd like attributes, please
|
||||
ignoreAttributes: false, // use attributes
|
||||
tagValueProcessor: (_tagName: string, tagValue: string /*, jPath, hasAttributes, isLeafNode*/) => {
|
||||
// since trimValues: false, we need to zap any element values that would be trimmed.
|
||||
return tagValue?.trim();
|
||||
|
|
@ -236,43 +236,6 @@ export class KeymanXMLReader {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requires attribute prefix @_ (double underscore)
|
||||
* For attributes, just remove @_ and continue.
|
||||
* For objects, replace any empty string "" with an empty object {} */
|
||||
private static fixupEmptyStringToEmptyObject_keylayout(data: any) : any {
|
||||
|
||||
if (typeof data === 'object') {
|
||||
// For arrays of objects, we map "" to {}
|
||||
// "" means an empty object
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(v => {
|
||||
if (v === '') {
|
||||
return {};
|
||||
} else {
|
||||
return KeymanXMLReader.fixupEmptyStringToEmptyObject_keylayout(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
// otherwise: remove @_ for attributes, remap objects
|
||||
const e: any = [];
|
||||
Object.entries(data).forEach(([k, v]) => {
|
||||
if (k.startsWith('@_')) {
|
||||
e.push([k.substring(3), KeymanXMLReader.fixupEmptyStringToEmptyObject_keylayout(v)]);
|
||||
} else {
|
||||
if (v === '') {
|
||||
e.push([k, {}]);
|
||||
} else {
|
||||
e.push([k, KeymanXMLReader.fixupEmptyStringToEmptyObject_keylayout(v)]);
|
||||
}
|
||||
}
|
||||
});
|
||||
return Object.fromEntries(e);
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Replace:
|
||||
* ```json
|
||||
|
|
@ -338,8 +301,6 @@ export class KeymanXMLReader {
|
|||
let result = parser.parse(data, true);
|
||||
if (PARSER_OPTIONS[this.type].attributeNamePrefix === '$') {
|
||||
result = KeymanXMLReader.fixupDollarAttributes(result);
|
||||
} else if (PARSER_OPTIONS[this.type].attributeNamePrefix === '@_') {
|
||||
result = KeymanXMLReader.fixupEmptyStringToEmptyObject_keylayout(result);
|
||||
} else if (PARSER_OPTIONS[this.type].attributeNamePrefix === '@__') {
|
||||
result = KeymanXMLReader.fixupEmptyStringToEmptyObject(result);
|
||||
} else if (PARSER_OPTIONS[this.type].preserveOrder) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "${THIS_SCRIPT%/*}/../../../resources/build/builder-full.inc.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
|
@ -30,15 +31,6 @@ builder_parse "$@"
|
|||
|
||||
#-------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
do_kmc_convert_test() {
|
||||
|
||||
builder_echo heading "Creating keylayout.schema.JSON"
|
||||
"$KEYMAN_ROOT/resources/standards-data/keylayout/create_keylayout_schema.sh"
|
||||
|
||||
builder_echo heading "Creating keylayout.schema.validator"
|
||||
"$KEYMAN_ROOT/common/web/types/build.sh" "configure"
|
||||
}
|
||||
|
||||
builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo
|
||||
builder_run_action configure node_select_version_and_npm_ci
|
||||
builder_run_action build tsc --build
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@
|
|||
"url": "https://github.com/keymanapp/keyman/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@keymanapp/developer-utils": "*",
|
||||
"ajv": "^8.17.1"
|
||||
"@keymanapp/developer-utils": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@keymanapp/developer-test-helpers": "*",
|
||||
|
|
@ -38,6 +37,9 @@
|
|||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^20.4.1",
|
||||
"@types/semver": "^7.3.12",
|
||||
"ajv": "^8.12.0",
|
||||
"ajv-cli": "^5.0.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"c8": "^7.12.0",
|
||||
"chalk": "^2.4.2",
|
||||
"typescript": "^5.4.5"
|
||||
|
|
@ -64,4 +66,4 @@
|
|||
"type": "git",
|
||||
"url": "git+https://github.com/keymanapp/keyman.git"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Output artifacts available from kmc-convert
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Lists all the available converters and finds matching converter
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Converter messages
|
||||
*/
|
||||
|
|
@ -29,11 +29,10 @@ export class ConverterMessages {
|
|||
);
|
||||
|
||||
static ERROR_FileNotFound = SevError | 0x0003;
|
||||
static Error_FileNotFound =
|
||||
(o: { inputFilename: string; }) => m(
|
||||
this.ERROR_FileNotFound,
|
||||
`Input filename '${def(o.inputFilename)}' does not exist or could not be loaded.`
|
||||
);
|
||||
static Error_FileNotFound = (o: { inputFilename: string; }) => m(
|
||||
this.ERROR_FileNotFound,
|
||||
`Input filename '${def(o.inputFilename)}' does not exist or could not be loaded.`
|
||||
);
|
||||
|
||||
static ERROR_UnableToRead = SevError | 0x0004;
|
||||
static Error_UnableToRead = (o: { inputFilename: string; }) => m(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Converter options
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Infrastructure for keyboard source file conversion tools
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7,13 +7,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { CompilerCallbacks } from "@keymanapp/developer-utils";
|
||||
import { XMLParser } from 'fast-xml-parser';
|
||||
import { util } from '@keymanapp/common-types';
|
||||
import { CompilerCallbacks, DeveloperUtilsMessages, Keylayout } from "@keymanapp/developer-utils";
|
||||
import { util, SchemaValidators } from '@keymanapp/common-types';
|
||||
import { ConverterMessages } from '../converter-messages.js';
|
||||
import { SchemaValidators } from '@keymanapp/common-types';
|
||||
import { DeveloperUtilsMessages } from '@keymanapp/developer-utils';
|
||||
import { KeylayoutXMLSourceFile } from "@keymanapp/developer-utils";
|
||||
|
||||
import boxXmlArray = util.boxXmlArray;
|
||||
|
||||
|
|
@ -24,7 +21,7 @@ export class KeylayoutFileReader {
|
|||
/**
|
||||
* @returns true if valid, false if invalid
|
||||
*/
|
||||
public validate(source: KeylayoutXMLSourceFile): boolean {
|
||||
public validate(source: Keylayout.KeylayoutXMLSourceFile): boolean {
|
||||
if (!SchemaValidators.default.keylayout(source)) {
|
||||
for (const err of (<any>SchemaValidators.default.keylayout).errors) {
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_InvalidXml({
|
||||
|
|
@ -41,7 +38,7 @@ export class KeylayoutFileReader {
|
|||
* @param o Object with possible property #text containing whitespaces
|
||||
* @return objects that do not contain property #text
|
||||
*/
|
||||
public remove_whitespace(o: any): void {
|
||||
public removeWhitespace(o: any): void {
|
||||
if (o['#text']) {
|
||||
delete o['#text'];
|
||||
}
|
||||
|
|
@ -53,9 +50,9 @@ export class KeylayoutFileReader {
|
|||
* @param x Name of element to box
|
||||
* @return objects that contain only boxed arrays
|
||||
*/
|
||||
public removeWhitespace_boxArray(o: any, x: string): void {
|
||||
public removeWhitespaceBoxArray(o: any, x: string): void {
|
||||
|
||||
this.remove_whitespace(o);
|
||||
this.removeWhitespace(o);
|
||||
boxXmlArray(o, x);
|
||||
}
|
||||
|
||||
|
|
@ -66,34 +63,34 @@ export class KeylayoutFileReader {
|
|||
*/
|
||||
public boxArray(source: any) {
|
||||
|
||||
this.remove_whitespace(source);
|
||||
this.removeWhitespace(source);
|
||||
|
||||
this.removeWhitespace_boxArray(source, 'keyMapSet');
|
||||
this.removeWhitespaceBoxArray(source, 'keyMapSet');
|
||||
|
||||
this.removeWhitespace_boxArray(source.layouts, 'layout');
|
||||
this.removeWhitespace_boxArray(source?.modifierMap, 'keyMapSelect');
|
||||
this.removeWhitespaceBoxArray(source.layouts, 'layout');
|
||||
this.removeWhitespaceBoxArray(source?.modifierMap, 'keyMapSelect');
|
||||
|
||||
for (const keyMapSelect of source?.modifierMap?.keyMapSelect) {
|
||||
this.removeWhitespace_boxArray(keyMapSelect, 'modifier');
|
||||
this.removeWhitespaceBoxArray(keyMapSelect, 'modifier');
|
||||
}
|
||||
|
||||
this.removeWhitespace_boxArray(source.keyMapSet[0], 'keyMap');
|
||||
this.removeWhitespaceBoxArray(source.keyMapSet[0], 'keyMap');
|
||||
|
||||
for (const keyMapSet of source?.keyMapSet) {
|
||||
for (const keyMap of keyMapSet.keyMap) {
|
||||
this.removeWhitespace_boxArray(keyMap, 'key');
|
||||
this.removeWhitespaceBoxArray(keyMap, 'key');
|
||||
}
|
||||
this.removeWhitespace_boxArray(keyMapSet, 'keyMap');
|
||||
this.removeWhitespaceBoxArray(keyMapSet, 'keyMap');
|
||||
}
|
||||
|
||||
this.removeWhitespace_boxArray(source?.actions, 'action');
|
||||
this.removeWhitespaceBoxArray(source?.actions, 'action');
|
||||
for (const action of source?.actions?.action) {
|
||||
this.removeWhitespace_boxArray(action, 'when');
|
||||
this.removeWhitespaceBoxArray(action, 'when');
|
||||
}
|
||||
|
||||
this.removeWhitespace_boxArray(source.terminators, 'when');
|
||||
this.removeWhitespaceBoxArray(source.terminators, 'when');
|
||||
for (const action of source?.actions?.action) {
|
||||
this.removeWhitespace_boxArray(action, 'when');
|
||||
this.removeWhitespaceBoxArray(action, 'when');
|
||||
}
|
||||
|
||||
return source;
|
||||
|
|
@ -105,13 +102,13 @@ export class KeylayoutFileReader {
|
|||
* @param inputFilename the ukelele .keylayout-file to be parsed
|
||||
* @return in case of success: json object containing data of the .keylayout file; else null
|
||||
*/
|
||||
public read(inputFilename: string): KeylayoutXMLSourceFile {
|
||||
public read(inputFilename: string): Keylayout.KeylayoutXMLSourceFile {
|
||||
|
||||
const options = {
|
||||
ignoreAttributes: [''], // we do not process an output character of ""
|
||||
trimValues: false, // we do not trim values because if we do we cannot process an output character of " " (space)
|
||||
parseTagValue: false,
|
||||
attributeNamePrefix: '@_', // to access the attribute
|
||||
attributeNamePrefix: '@__', // to access the attribute
|
||||
ignoreDeclaration: true
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Keyboard source file conversion tools
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import 'mocha';
|
||||
import { ConverterMessages } from '../src/converter-messages.js';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Helpers and utilities for the Mocha tests.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[makePathToFixture('../data/Test_MissingActionsERROR.keylayout')],
|
||||
[makePathToFixture('../data/Test_MissingTerminatorsERROR.keylayout')],
|
||||
[makePathToFixture('../data/Test_MissingAllERROR.keylayout')],
|
||||
].forEach(function (files_) {
|
||||
it(files_ + " should give an error ", async function () {
|
||||
sut.run(files_[0]);
|
||||
].forEach(function (files) {
|
||||
it(files + " should give an error ", async function () {
|
||||
sut.run(files[0]);
|
||||
assert.isTrue(compilerTestCallbacks.messages.length > 0);
|
||||
});
|
||||
});
|
||||
|
|
@ -66,18 +66,9 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[makePathToFixture('../data/Test_ambiguous_keys.keylayout')],
|
||||
[makePathToFixture('../data/Test_nr_elements.keylayout')],
|
||||
[makePathToFixture('../data/Test.keylayout')],
|
||||
// [makePathToFixture('../data/Test_mixedEncodings.keylayout')],
|
||||
|
||||
/*
|
||||
].forEach(function (files) {
|
||||
it(files + " should give no errors ", async function () {
|
||||
sut.run(files[0]);
|
||||
>>>>>>> feat/developer/kmc-convert*/
|
||||
|
||||
|
||||
].forEach(function (files_) {
|
||||
it(files_ + " should give no errors ", async function () {
|
||||
sut.run(files_[0]);
|
||||
assert.isTrue(compilerTestCallbacks.messages.length === 0);
|
||||
});
|
||||
});
|
||||
|
|
@ -117,7 +108,6 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: null }));
|
||||
});
|
||||
|
||||
|
||||
it('run() should throw on null input file name and unknown output file name', async function () {
|
||||
const result = sut.run(null, 'X');
|
||||
assert.isNotNull(result);
|
||||
|
|
@ -129,105 +119,111 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
const inputFilename = makePathToFixture('../data/Unavailable.keylayout');
|
||||
const result = sut.run(inputFilename, null);
|
||||
assert.isNotNull(result);
|
||||
assert.equal(compilerTestCallbacks.messages.length, 1);
|
||||
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_OutputFilenameIsRequired());
|
||||
assert.equal(compilerTestCallbacks.messages.length, 2);
|
||||
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_UnableToRead({ inputFilename }));
|
||||
assert.equal(compilerTestCallbacks.messages[1].code, 5246984);
|
||||
});
|
||||
|
||||
it('run() should throw on and null output file name', async function () {
|
||||
it('run() should return on available input file name and null output file name', async function () {
|
||||
this.timeout(5000); // allow longer time for this test
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const result = sut.run(inputFilename, null);
|
||||
assert.isNotNull(result);
|
||||
assert.equal(compilerTestCallbacks.messages.length, 1);
|
||||
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_OutputFilenameIsRequired());
|
||||
await NodeAssert.doesNotReject(async () => sut.run(inputFilename, null));
|
||||
assert.equal(compilerTestCallbacks.messages.length, 0);
|
||||
});
|
||||
|
||||
it('run() should return on correct input file name and empty output file name ', async function () {
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
await NodeAssert.doesNotReject(async () => sut.run(inputFilename, ''));
|
||||
assert.equal(compilerTestCallbacks.messages.length, 0);
|
||||
});
|
||||
|
||||
it('run() should return on correct input file name and null output file name', async function () {
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
await NodeAssert.doesNotReject(async () => sut.run(inputFilename, null));
|
||||
assert.equal(compilerTestCallbacks.messages.length, 0);
|
||||
});
|
||||
|
||||
it('run() should return on correct input file name and given output file name ', async function () {
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const outputFilename = makePathToFixture('../data/OutputName.kmn');
|
||||
await NodeAssert.doesNotReject(async () => sut.run(inputFilename, outputFilename));
|
||||
assert.equal(compilerTestCallbacks.messages.length, 0);
|
||||
});
|
||||
|
||||
it('run() return on correct input file extention and unsupperted output file extention', async function () {
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const outputFilename = makePathToFixture('../data/OutputXName.B');
|
||||
await NodeAssert.doesNotReject(async () => sut.run(inputFilename, outputFilename));
|
||||
assert.equal(compilerTestCallbacks.messages.length, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('convert() ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
|
||||
// ProcesData from usable file
|
||||
// ProcessedData from usable file
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const converted = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
const read = sutR.read(inputFilename);
|
||||
const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
|
||||
// ProcesData from unavailable file
|
||||
const inputFilename_unavailable = makePathToFixture('../data/X.keylayout');
|
||||
const read_unavailable = sut_r.read(inputFilename_unavailable);
|
||||
const converted_unavailable = sut.convert_bound.convert(read_unavailable, inputFilename_unavailable.replace(/\.keylayout$/, '.kmn'));
|
||||
// ProcessedData from unavailable file
|
||||
const inputFilenameUnavailable = makePathToFixture('../data/X.keylayout');
|
||||
const readUnavailable = sutR.read(inputFilenameUnavailable);
|
||||
const convertedUnavailable = sut.convertBound.convert(readUnavailable, inputFilenameUnavailable.replace(/\.keylayout$/, '.kmn'));
|
||||
|
||||
// ProcesData from empty file
|
||||
const inputFilename_empty = makePathToFixture('');
|
||||
const read_empty = sut_r.read(inputFilename_empty);
|
||||
const converted_empty = sut.convert_bound.convert(read_empty, inputFilename_empty);
|
||||
// ProcessedData from empty file
|
||||
const inputFilenameEmpty = makePathToFixture('');
|
||||
const readEmpty = sutR.read(inputFilenameEmpty);
|
||||
const convertedEmpty = sut.convertBound.convert(readEmpty, inputFilenameEmpty);
|
||||
|
||||
it('should return converted array on correct input', async function () {
|
||||
assert.isTrue(converted.arrayOf_Rules.length !== 0);
|
||||
assert.isTrue(converted.arrayOfRules.length !== 0);
|
||||
});
|
||||
|
||||
it('should return empty on empty input', async function () {
|
||||
assert.isTrue((converted_empty.keylayout_filename === ''
|
||||
&& converted_empty.arrayOf_Modifiers.length === 0
|
||||
&& converted_empty.arrayOf_Rules.length === 0));
|
||||
assert.isTrue((convertedEmpty.keylayoutFilename === ''
|
||||
&& convertedEmpty.arrayOfModifiers.length === 0
|
||||
&& convertedEmpty.arrayOfRules.length === 0));
|
||||
});
|
||||
|
||||
it('should return empty on only name as input', async function () {
|
||||
assert.isTrue((converted_unavailable.keylayout_filename === ''
|
||||
&& converted_unavailable.arrayOf_Modifiers.length === 0
|
||||
&& converted_unavailable.arrayOf_Rules.length === 0));
|
||||
assert.isTrue((convertedUnavailable.keylayoutFilename === ''
|
||||
&& convertedUnavailable.arrayOfModifiers.length === 0
|
||||
&& convertedUnavailable.arrayOfRules.length === 0));
|
||||
});
|
||||
|
||||
it('should return empty on only modifiers as input', async function () {
|
||||
const converted_mod = sut.convert_bound.convert({
|
||||
keylayout_filename: '',
|
||||
arrayOf_Modifiers: [['caps'], ['Shift'], ['command']],
|
||||
arrayOf_Rules: []
|
||||
const convertedMod = sut.convertBound.convert({
|
||||
keylayoutFilename: '',
|
||||
arrayOfModifiers: [['caps'], ['Shift'], ['command']],
|
||||
arrayOfRules: []
|
||||
}, '');
|
||||
assert.isTrue((converted_mod.keylayout_filename === ''
|
||||
&& converted_mod.arrayOf_Modifiers.length === 0
|
||||
&& converted_mod.arrayOf_Rules.length === 0));
|
||||
assert.isTrue((convertedMod.keylayoutFilename === ''
|
||||
&& convertedMod.arrayOfModifiers.length === 0
|
||||
&& convertedMod.arrayOfRules.length === 0));
|
||||
});
|
||||
|
||||
it('should return empty on only rules as input', async function () {
|
||||
const converted_rule = sut.convert_bound.convert({
|
||||
keylayout_filename: '',
|
||||
arrayOf_Modifiers: [],
|
||||
arrayOf_Rules: [['C0', '', '', 0, 0, '', '', 0, 0, 'CAPS', 'K_A', 'A']]
|
||||
const convertedRule = sut.convertBound.convert({
|
||||
keylayoutFilename: '',
|
||||
arrayOfModifiers: [],
|
||||
arrayOfRules: [['C0', '', '', 0, 0, '', '', 0, 0, 'CAPS', 'K_A', 'A']]
|
||||
}, '');
|
||||
assert.isTrue((converted_rule.keylayout_filename === ''
|
||||
&& converted_rule.arrayOf_Modifiers.length === 0
|
||||
&& converted_rule.arrayOf_Rules.length === 0));
|
||||
assert.isTrue((convertedRule.keylayoutFilename === ''
|
||||
&& convertedRule.arrayOfModifiers.length === 0
|
||||
&& convertedRule.arrayOfRules.length === 0));
|
||||
});
|
||||
|
||||
it('should return empty array of rules on null input', async function () {
|
||||
const converted_rule = sut.convert_bound.convert(null, 'ABC.kmn');
|
||||
assert.isTrue(converted_rule.arrayOf_Rules.length === 0);
|
||||
const convertedRule = sut.convertBound.convert(null, 'ABC.kmn');
|
||||
assert.isTrue(convertedRule.arrayOfRules.length === 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('create_kmn_modifier ', function () {
|
||||
describe('createKmnModifier ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
|
||||
[
|
||||
|
|
@ -263,7 +259,7 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
['roption', true, 'NCAPS RALT'],
|
||||
].forEach(function (values) {
|
||||
it(('should convert "' + values[0] + '"').padEnd(36, " ") + 'to "' + values[2] + '"', async function () {
|
||||
const result = sut.create_kmn_modifier(values[0] as string, values[1] as boolean);
|
||||
const result = sut.createKmnModifier(values[0] as string, values[1] as boolean);
|
||||
assert.equal(result, values[2]);
|
||||
});
|
||||
});
|
||||
|
|
@ -294,7 +290,7 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('map_UkeleleKC_To_VK ', function () {
|
||||
describe('mapUkeleleKeycodeToVK ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
[
|
||||
[0x00, 'K_A'],
|
||||
|
|
@ -309,8 +305,8 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[undefined, ''],
|
||||
[, ''],
|
||||
].forEach(function (values) {
|
||||
it(("map_UkeleleKC_To_VK(" + values[0] + ")").padEnd(26, " ") + "should return " + "'" + values[1] + "'", async function () {
|
||||
const result = sut.map_UkeleleKC_To_VK(values[0] as number);
|
||||
it(("mapUkeleleKeycodeToVK(" + values[0] + ")").padEnd(26, " ") + "should return " + "'" + values[1] + "'", async function () {
|
||||
const result = sut.mapUkeleleKeycodeToVK(values[0] as number);
|
||||
assert.equal(result, values[1]);
|
||||
});
|
||||
});
|
||||
|
|
@ -336,12 +332,12 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('get_Modifier_array__From__KeyModifier_array ', function () {
|
||||
describe('getModifierArrayFromKeyModifierArray ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const converted = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
const read = sutR.read(inputFilename);
|
||||
const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
[
|
||||
[[{ key: '0', behaviour: 0 }], [['', 'shift? caps? ']]],
|
||||
[[{ key: '0', behaviour: 2 }], [['shift? leftShift caps? ', 'anyShift caps?', 'shift leftShift caps ', 'shift? rightShift caps? ']]],
|
||||
|
|
@ -353,19 +349,19 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
|
||||
].forEach(function (values) {
|
||||
it((values[1] !== null) ?
|
||||
("get_Modifier_array__From__KeyModifier_array('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + JSON.stringify(values[1]) + "'" :
|
||||
("get_Modifier_array__From__KeyModifier_array('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + "null" + "'", async function () {
|
||||
const result = sut.get_Modifier_array__From__KeyModifier_array(converted.arrayOf_Modifiers, values[0] as KeylayoutFileData[]);
|
||||
("getModifierArrayFromKeyModifierArray('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + JSON.stringify(values[1]) + "'" :
|
||||
("getModifierArrayFromKeyModifierArray('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + "null" + "'", async function () {
|
||||
const result = sut.getModifierArrayFromKeyModifierArray(converted.arrayOfModifiers, values[0] as KeylayoutFileData[]);
|
||||
assert.deepStrictEqual(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get_KeyModifier_array__From__ActionID ', function () {
|
||||
describe('getKeyModifierArrayFromActionID ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const read = sutR.read(inputFilename);
|
||||
[
|
||||
['A_16', [{ "key": "32", "behaviour": "5" }]],
|
||||
['A_19', [{ "key": "45", "behaviour": "5" }]],
|
||||
|
|
@ -380,18 +376,18 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
for (let i = 0; i < values[1].length; i++) {
|
||||
outstring = outstring + "[ " + JSON.stringify(values[1][i]) + "], ";
|
||||
}
|
||||
it(("get_KeyModifier_array__From__ActionID('" + values[0] + "')").padEnd(57, " ") + ' should return ' + outstring.substring(0, outstring.lastIndexOf(']') + 2) + " ]", async function () {
|
||||
const result = sut.get_KeyModifier_array__From__ActionID(read, String(values[0]));
|
||||
it(("getKeyModifierArrayFromActionID('" + values[0] + "')").padEnd(57, " ") + ' should return ' + outstring.substring(0, outstring.lastIndexOf(']') + 2) + " ]", async function () {
|
||||
const result = sut.getKeyModifierArrayFromActionID(read, String(values[0]));
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get_ActionID__From__ActionNext ', function () {
|
||||
describe('getActionIdFromActionNext ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const read = sutR.read(inputFilename);
|
||||
|
||||
[
|
||||
['none', ''],
|
||||
|
|
@ -407,17 +403,17 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[undefined, ''],
|
||||
['unknown', ''],
|
||||
].forEach(function (values) {
|
||||
it(("get_ActionID__From__ActionNext('" + values[0] + "')").padEnd(49, " ") + ' should return ' + "'" + values[1] + "'", async function () {
|
||||
const result = sut.get_ActionID__From__ActionNext(read, String(values[0]));
|
||||
it(("getActionIdFromActionNext('" + values[0] + "')").padEnd(49, " ") + ' should return ' + "'" + values[1] + "'", async function () {
|
||||
const result = sut.getActionIdFromActionNext(read, String(values[0]));
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('get_ActionIndex__From__ActionId ', function () {
|
||||
describe('getActionIndexFromActionId ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const read = sutR.read(inputFilename);
|
||||
|
||||
[
|
||||
['none', 0],
|
||||
|
|
@ -431,17 +427,17 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[undefined, 0],
|
||||
['unknown', 0],
|
||||
].forEach(function (values) {
|
||||
it(("get_ActionIndex__From__ActionId('" + values[0] + "')").padEnd(50, " ") + ' should return ' + values[1], async function () {
|
||||
const result = sut.get_ActionIndex__From__ActionId(read, String(values[0]));
|
||||
it(("getActionIndexFromActionId('" + values[0] + "')").padEnd(50, " ") + ' should return ' + values[1], async function () {
|
||||
const result = sut.getActionIndexFromActionId(read, String(values[0]));
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('get_Output__From__ActionId_None ', function () {
|
||||
describe('getOutputFromActionIdNone ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const read = sutR.read(inputFilename);
|
||||
|
||||
[
|
||||
['A_14', 'u'],
|
||||
|
|
@ -451,8 +447,8 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
['unknown', ''],
|
||||
].forEach(function (values) {
|
||||
it(
|
||||
("get_Output__From__ActionId_None('" + values[0] + "')").padEnd(56, " ") + ' should return ' + "'" + values[1] + "'", async function () {
|
||||
const result = sut.get_Output__From__ActionId_None(read, String(values[0]));
|
||||
("getOutputFromActionIdNone('" + values[0] + "')").padEnd(56, " ") + ' should return ' + "'" + values[1] + "'", async function () {
|
||||
const result = sut.getOutputFromActionIdNone(read, String(values[0]));
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
|
|
@ -461,19 +457,19 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[undefined, ''],
|
||||
[99, ''],
|
||||
].forEach(function (values) {
|
||||
it(("get_Output__From__ActionId_None('" + values[0] + "')").padEnd(56, " ") + ' should return ' + values[1], async function () {
|
||||
const result = sut.get_Output__From__ActionId_None(read, String(values[0]));
|
||||
it(("getOutputFromActionIdNone('" + values[0] + "')").padEnd(56, " ") + ' should return ' + values[1], async function () {
|
||||
const result = sut.getOutputFromActionIdNone(read, String(values[0]));
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array ', function () {
|
||||
describe('getKeyBehaviourModOutputArrayFromKeyActionBehaviourOutputArray ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const read = sutR.read(inputFilename);
|
||||
|
||||
const b1_keycode_arr: KeylayoutFileData[] = [
|
||||
const b1KeycodeArr: KeylayoutFileData[] = [
|
||||
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', outchar: 'ˆ' },
|
||||
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '1', outchar: 'ˆ' },
|
||||
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '2', outchar: 'ˆ' },
|
||||
|
|
@ -498,7 +494,7 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
{ keyCode: '0', key: 'K_A', actionId: 'A_9', behaviour: '0', outchar: 'â' }
|
||||
|
||||
];
|
||||
const b1_modifierKey_arr: KeylayoutFileData[] = [
|
||||
const b1ModifierKeyArr: KeylayoutFileData[] = [
|
||||
{ actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' },
|
||||
{ actionId: 'A_0', key: 'K_SPACE', behaviour: '1', modifier: 'CAPS', outchar: 'ˆ' },
|
||||
{ actionId: 'A_0', key: 'K_SPACE', behaviour: '2', modifier: 'NCAPS SHIFT', outchar: 'ˆ' },
|
||||
|
|
@ -530,7 +526,7 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
{ actionId: 'A_9', key: 'K_A', behaviour: '0', modifier: 'NCAPS', outchar: 'â' }
|
||||
];
|
||||
|
||||
[[b1_keycode_arr, b1_modifierKey_arr],
|
||||
[[b1KeycodeArr, b1ModifierKeyArr],
|
||||
[[{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', modifier: '0', outchar: 'ˆ' }], [{ actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' }]],
|
||||
[[{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', modifier: '', outchar: 'ˆ' }], [{ actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' }]],
|
||||
[[{ keyCode: '49', key: 'K_SPACE', actionId: '', behaviour: '0', modifier: '0', outchar: 'ˆ' }], [{ actionId: '', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' }]],
|
||||
|
|
@ -538,13 +534,13 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[[{ keyCode: '', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', modifier: '0', outchar: 'ˆ' }], [{ actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' }]],
|
||||
[[{ keyCode: '', key: '', actionId: '', behaviour: '0', modifier: '', outchar: '' }], [{ actionId: '', key: '', behaviour: '0', modifier: 'NCAPS', outchar: '' }]],
|
||||
].forEach(function (values) {
|
||||
const isCaps_used = true;
|
||||
const string_in = "get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(['" + "', '" + "', '" + values[0][0].keyCode + "', '" + values[0][0].key + "', '" + values[0][0].actionId + "', '" + values[0][0].modifier + "', '" + values[0][0].outchar + "'])";
|
||||
const string_out = "['" + "', '" + "', '" + values[1][0].key + "', '" + values[1][0].actionId + "', '" + "', '" + values[1][0].modifier + "', '" + values[1][0].outchar + "']";
|
||||
const isCapsUsed = true;
|
||||
const stringIn = "getKeyBehaviourModOutputArrayFromKeyActionBehaviourOutputArray(['" + "', '" + "', '" + values[0][0].keyCode + "', '" + values[0][0].key + "', '" + values[0][0].actionId + "', '" + values[0][0].modifier + "', '" + values[0][0].outchar + "'])";
|
||||
const stringOut = "['" + "', '" + "', '" + values[1][0].key + "', '" + values[1][0].actionId + "', '" + "', '" + values[1][0].modifier + "', '" + values[1][0].outchar + "']";
|
||||
|
||||
it((JSON.stringify(values[1]).length > 60) ? 'an array of objects should return an array of objects' :
|
||||
string_in.padEnd(74, " ") + ' should return ' + string_out, async function () {
|
||||
const result = sut.get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(read, values[0], isCaps_used);
|
||||
stringIn.padEnd(74, " ") + ' should return ' + stringOut, async function () {
|
||||
const result = sut.getKeyBehaviourModOutputArrayFromKeyActionBehaviourOutputArray(read, values[0], isCapsUsed);
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
|
|
@ -553,12 +549,12 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[{ keyCode: '', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', modifier: '0', outchar: 'ˆ' }, { actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: '', outchar: 'ˆ' }],
|
||||
[{ keyCode: '', key: '', actionId: '', behaviour: '0', modifier: '', outchar: '' }, { actionId: '', key: '', behaviour: '0', modifier: '', outchar: '' }],
|
||||
].forEach(function (values) {
|
||||
const isCaps_used = false;
|
||||
const string_in = "get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array([ '" + values[0].keyCode + "', '" + values[0].key + "', '" + values[0].actionId + "', '" + values[0].modifier + "', '" + values[0].outchar + "'])";
|
||||
const string_out = "['" + values[1].actionId + "', '" + "', '" + values[1].modifier + "', '" + values[1].key + "', '" + values[1].outchar + "']";
|
||||
const isCapsUsed = false;
|
||||
const stringIn = "getKeyBehaviourModOutputArrayFromKeyActionBehaviourOutputArray([ '" + values[0].keyCode + "', '" + values[0].key + "', '" + values[0].actionId + "', '" + values[0].modifier + "', '" + values[0].outchar + "'])";
|
||||
const stringOut = "['" + values[1].actionId + "', '" + "', '" + values[1].modifier + "', '" + values[1].key + "', '" + values[1].outchar + "']";
|
||||
|
||||
it(string_in.padEnd(74, " ") + ' should return ' + string_out, async function () {
|
||||
const result = sut.get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(read, [values[0]], isCaps_used);
|
||||
it(stringIn.padEnd(74, " ") + ' should return ' + stringOut, async function () {
|
||||
const result = sut.getKeyBehaviourModOutputArrayFromKeyActionBehaviourOutputArray(read, [values[0]], isCapsUsed);
|
||||
assert.equal(JSON.stringify(result), JSON.stringify([values[1]]));
|
||||
});
|
||||
});
|
||||
|
|
@ -568,17 +564,17 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[null, []],
|
||||
].forEach(function (values) {
|
||||
const isCaps = true;
|
||||
it(("get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array([" + values[0] + "])").padEnd(74, " ") + ' should return ' + "[" + values[1] + "]", async function () {
|
||||
const result = sut.get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(read, values[0], isCaps);
|
||||
it(("getKeyBehaviourModOutputArrayFromKeyActionBehaviourOutputArray([" + values[0] + "])").padEnd(74, " ") + ' should return ' + "[" + values[1] + "]", async function () {
|
||||
const result = sut.getKeyBehaviourModOutputArrayFromKeyActionBehaviourOutputArray(read, values[0], isCaps);
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('get_ActionStateOutput_array__From__ActionState ', function () {
|
||||
describe('getActionStateOutputArrayFromActionState ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const read = sutR.read(inputFilename);
|
||||
|
||||
[['1', [
|
||||
{ "id": "A_0", "state": "1", "output": "ˆ" },
|
||||
|
|
@ -614,19 +610,19 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[undefined, [],],
|
||||
].forEach(function (values) {
|
||||
it((JSON.stringify(values[1]).length > 30) ?
|
||||
("get_ActionStateOutput_array__From__ActionState('" + values[0] + "')").padEnd(60, " ") + ' should return an array of objects' :
|
||||
("get_ActionStateOutput_array__From__ActionState('" + values[0] + "')").padEnd(60, " ") + ' should return ' + "'" + JSON.stringify(values[1]) + "'", async function () {
|
||||
const result = sut.get_ActionStateOutput_array__From__ActionState(read, String(values[0]));
|
||||
("getActionStateOutputArrayFromActionState('" + values[0] + "')").padEnd(60, " ") + ' should return an array of objects' :
|
||||
("getActionStateOutputArrayFromActionState('" + values[0] + "')").padEnd(60, " ") + ' should return ' + "'" + JSON.stringify(values[1]) + "'", async function () {
|
||||
const result = sut.getActionStateOutputArrayFromActionState(read, String(values[0]));
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput ', function () {
|
||||
describe('getActionOutputBehaviourKeyModiFromActionIDStateOutput ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const converted = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
const read = sutR.read(inputFilename);
|
||||
const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
|
||||
[
|
||||
['A_1', 'A', true,
|
||||
|
|
@ -650,20 +646,20 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
|
||||
].forEach(function (values) {
|
||||
it((JSON.stringify(values[3]).length > 35) ?
|
||||
("get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return an array of objects' :
|
||||
("get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return ' + "'" + JSON.stringify(values[3]) + "'", async function () {
|
||||
const result = sut.get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput(read, converted.arrayOf_Modifiers, String(values[0]), String(values[1]), Boolean(values[2]));
|
||||
("getActionOutputBehaviourKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return an array of objects' :
|
||||
("getActionOutputBehaviourKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return ' + "'" + JSON.stringify(values[3]) + "'", async function () {
|
||||
const result = sut.getActionOutputBehaviourKeyModiFromActionIDStateOutput(read, converted.arrayOfModifiers, String(values[0]), String(values[1]), Boolean(values[2]));
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[3]));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('get_KeyActionOutput_array__From__ActionStateOutput_array ', function () {
|
||||
describe('getKeyActionOutputArrayFromActionStateOutputArray ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const read = sutR.read(inputFilename);
|
||||
|
||||
const b6_actionId_arr: ActionStateOutput[] = [
|
||||
const b6ActionIdArr: ActionStateOutput[] = [
|
||||
{ "id": "A_0", "state": "1", "output": "ˆ" },
|
||||
{ "id": "A_1", "state": "1", "output": "Â" },
|
||||
{ "id": "A_10", "state": "1", "output": "ê" },
|
||||
|
|
@ -677,7 +673,7 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
{ "id": "A_9", "state": "1", "output": "â" }
|
||||
];
|
||||
|
||||
const b1_keycode_arr: KeylayoutFileData[] = [
|
||||
const b1KeycodeArr: KeylayoutFileData[] = [
|
||||
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', outchar: 'ˆ' },
|
||||
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '1', outchar: 'ˆ' },
|
||||
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '2', outchar: 'ˆ' },
|
||||
|
|
@ -702,10 +698,10 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
{ keyCode: '0', key: 'K_A', actionId: 'A_9', behaviour: '0', outchar: 'â' }
|
||||
];
|
||||
|
||||
[[b6_actionId_arr, b1_keycode_arr],
|
||||
[[b6ActionIdArr, b1KeycodeArr],
|
||||
].forEach(function (values) {
|
||||
it(("get_KeyActionOutput_array__From__ActionStateOutput_array([['" + JSON.stringify(values[0]) + "'],..])").padEnd(73, " ") + '1 should return an array of objects', async function () {
|
||||
const result = sut.get_KeyActionOutput_array__From__ActionStateOutput_array(read, values[0] as ActionStateOutput[]);
|
||||
it(("getKeyActionOutputArrayFromActionStateOutputArray([['" + JSON.stringify(values[0]) + "'],..])").padEnd(73, " ") + '1 should return an array of objects', async function () {
|
||||
const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read, values[0] as ActionStateOutput[]);
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
|
|
@ -734,8 +730,8 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[[{ "id": "A_0", "state": "1", "output": "" }], oneEntryResultNoOutput],
|
||||
[[{ "id": "A_0", "state": "", "output": "ˆ" }], oneEntryResult],
|
||||
].forEach(function (values) {
|
||||
it(("get_KeyActionOutput_array__From__ActionStateOutput_array(['" + JSON.stringify(values[0]) + "'])").padEnd(73, " ") + ' should return an array of objects', async function () {
|
||||
const result = sut.get_KeyActionOutput_array__From__ActionStateOutput_array(read, values[0] as ActionStateOutput[]);
|
||||
it(("getKeyActionOutputArrayFromActionStateOutputArray(['" + JSON.stringify(values[0]) + "'])").padEnd(73, " ") + ' should return an array of objects', async function () {
|
||||
const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read, values[0] as ActionStateOutput[]);
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
|
|
@ -745,8 +741,8 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[[{ "id": " ", "state": " ", "output": "" }], []],
|
||||
|
||||
].forEach(function (values) {
|
||||
it(("get_KeyActionOutput_array__From__ActionStateOutput_array(" + JSON.stringify(values[0]) + ")").padEnd(73, " ") + ' should return ' + "'[" + JSON.stringify(values[1]) + "]'", async function () {
|
||||
const result = sut.get_KeyActionOutput_array__From__ActionStateOutput_array(read, values[0] as ActionStateOutput[]);
|
||||
it(("getKeyActionOutputArrayFromActionStateOutputArray(" + JSON.stringify(values[0]) + ")").padEnd(73, " ") + ' should return ' + "'[" + JSON.stringify(values[1]) + "]'", async function () {
|
||||
const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read, values[0] as ActionStateOutput[]);
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
|
|
@ -755,8 +751,8 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
[undefined, []],
|
||||
[null, []],
|
||||
].forEach(function (values) {
|
||||
it(("get_KeyActionOutput_array__From__ActionStateOutput_array(" + JSON.stringify(values[0]) + ")").padEnd(73, " ") + ' should return ' + "'[" + JSON.stringify(values[1]) + "]'", async function () {
|
||||
const result = sut.get_KeyActionOutput_array__From__ActionStateOutput_array(read, values[0] as ActionStateOutput[]);
|
||||
it(("getKeyActionOutputArrayFromActionStateOutputArray(" + JSON.stringify(values[0]) + ")").padEnd(73, " ") + ' should return ' + "'[" + JSON.stringify(values[1]) + "]'", async function () {
|
||||
const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read, values[0] as ActionStateOutput[]);
|
||||
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
|
||||
});
|
||||
});
|
||||
|
|
@ -764,7 +760,7 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
|
||||
describe('createRuleData ', function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
|
||||
[
|
||||
[
|
||||
|
|
@ -816,9 +812,9 @@ describe('KeylayoutToKmnConverter', function () {
|
|||
].forEach(function (values: any) {
|
||||
it('data of \'' + values[0] + "' passed into createRuleData() " + 'should create an array of rules', async function () {
|
||||
const inputFilename = makePathToFixture(values[0][0]);
|
||||
const read = sut_r.read(inputFilename);
|
||||
const outArray = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
assert.deepEqual(outArray.arrayOf_Rules[0], values[1][0]);
|
||||
const read = sutR.read(inputFilename);
|
||||
const outArray = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
assert.deepEqual(outArray.arrayOfRules[0], values[1][0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import 'mocha';
|
||||
import { assert } from 'chai';
|
||||
import { KeylayoutXMLSourceFile } from "@keymanapp/developer-utils"
|
||||
import { Keylayout } from "@keymanapp/developer-utils"
|
||||
import { compilerTestCallbacks, makePathToFixture } from './helpers/index.js';
|
||||
import { KeylayoutFileReader } from '../src/keylayout-to-kmn/keylayout-file-reader.js';
|
||||
|
||||
|
|
@ -22,77 +22,77 @@ describe('KeylayoutFileReader', function () {
|
|||
describe("validate() ", function () {
|
||||
|
||||
it('validate() should return true on correct inputfile', async function () {
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const result: KeylayoutXMLSourceFile = sut_r.read(inputFilename);
|
||||
const validated = sut_r.validate(result);
|
||||
const result: Keylayout.KeylayoutXMLSourceFile = sutR.read(inputFilename);
|
||||
const validated = sutR.validate(result);
|
||||
assert.isTrue(validated);
|
||||
});
|
||||
|
||||
it('validate() should return false on inputfile with unknown tags', async function () {
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test_unknownTags.keylayout');
|
||||
const result: KeylayoutXMLSourceFile = sut_r.read(inputFilename);
|
||||
const validated = sut_r.validate(result);
|
||||
const result: Keylayout.KeylayoutXMLSourceFile = sutR.read(inputFilename);
|
||||
const validated = sutR.validate(result);
|
||||
assert.isFalse(validated);
|
||||
});
|
||||
|
||||
it('validate() should return false on inputfile with additional tags', async function () {
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test_additionalTags.keylayout');
|
||||
const result: KeylayoutXMLSourceFile = sut_r.read(inputFilename);
|
||||
const validated = sut_r.validate(result);
|
||||
const result: Keylayout.KeylayoutXMLSourceFile = sutR.read(inputFilename);
|
||||
const validated = sutR.validate(result);
|
||||
assert.isFalse(validated);
|
||||
});
|
||||
it('validate() should return false on inputfile with missing tags', async function () {
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test_missingTags.keylayout');
|
||||
const result: KeylayoutXMLSourceFile = sut_r.read(inputFilename);
|
||||
const validated = sut_r.validate(result);
|
||||
const result: Keylayout.KeylayoutXMLSourceFile = sutR.read(inputFilename);
|
||||
const validated = sutR.validate(result);
|
||||
assert.isFalse(validated);
|
||||
});
|
||||
it('validate() should return false on no entries in action-when', async function () {
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const inputFilename = makePathToFixture('../data/Test_noActionWhen.keylayout');
|
||||
const result: KeylayoutXMLSourceFile = sut_r.read(inputFilename);
|
||||
const validated = sut_r.validate(result);
|
||||
const result: Keylayout.KeylayoutXMLSourceFile = sutR.read(inputFilename);
|
||||
const validated = sutR.validate(result);
|
||||
assert.isFalse(validated);
|
||||
});
|
||||
});
|
||||
|
||||
describe("read() ", function () {
|
||||
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
|
||||
it('read() should return filled array on correct input', async function () {
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const result = sut_r.read(inputFilename);
|
||||
const result = sutR.read(inputFilename);
|
||||
assert.isNotEmpty(result);
|
||||
});
|
||||
|
||||
it('read() should return empty array on null input', async function () {
|
||||
const result = sut_r.read(null);
|
||||
const result = sutR.read(null);
|
||||
assert.isNull(result);
|
||||
});
|
||||
|
||||
it('read() should return empty array on empty input', async function () {
|
||||
const result = sut_r.read("");
|
||||
const result = sutR.read("");
|
||||
assert.isNull(result);
|
||||
});
|
||||
|
||||
it('read() should return empty array on space as input', async function () {
|
||||
const result = sut_r.read(" ");
|
||||
const result = sutR.read(" ");
|
||||
assert.isNull(result);
|
||||
});
|
||||
|
||||
it('read() should return empty array on unavailable file name', async function () {
|
||||
const inputFilename_unavailable = makePathToFixture('../data/X.keylayout');
|
||||
const result = sut_r.read(inputFilename_unavailable);
|
||||
const inputFilenameUnavailable = makePathToFixture('../data/X.keylayout');
|
||||
const result = sutR.read(inputFilenameUnavailable);
|
||||
assert.isNull(result);
|
||||
});
|
||||
|
||||
it('read() should return empty array on typo in path', async function () {
|
||||
const result = sut_r.read(makePathToFixture('../data|Test.keylayout'));
|
||||
const result = sutR.read(makePathToFixture('../data|Test.keylayout'));
|
||||
assert.isNull(result);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import 'mocha';
|
|||
import { assert } from 'chai';
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { compilerTestCallbacks, compilerTestOptions, makePathToFixture } from './helpers/index.js';
|
||||
import { KeylayoutToKmnConverter, ProcesData, Rule } from '../src/keylayout-to-kmn/keylayout-to-kmn-converter.js';
|
||||
import { KeylayoutToKmnConverter, ProcessedData, Rule } from '../src/keylayout-to-kmn/keylayout-to-kmn-converter.js';
|
||||
import { KmnFileWriter } from '../src/keylayout-to-kmn/kmn-file-writer.js';
|
||||
import { KeylayoutFileReader } from '../src/keylayout-to-kmn/keylayout-file-reader.js';
|
||||
import { ConverterMessages } from '../src/converter-messages.js';
|
||||
|
|
@ -25,10 +25,10 @@ describe('KmnFileWriter', function () {
|
|||
describe("write() ", function () {
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sut_w = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const read = sut_r.read(inputFilename);
|
||||
const converted = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const read = sutR.read(inputFilename);
|
||||
const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
|
||||
// empty ProcesData from unavailable file name
|
||||
const inputFilename_unavailable = makePathToFixture('../data/X.keylayout');
|
||||
|
|
@ -46,56 +46,56 @@ describe('KmnFileWriter', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe("writeData_Rules() ", function () {
|
||||
describe("writeDataRules() ", function () {
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sut_w = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const read = sut_r.read(inputFilename);
|
||||
const converted = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const read = sutR.read(inputFilename);
|
||||
const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
|
||||
// empty ProcesData from unavailable file name
|
||||
const inputFilename_unavailable = makePathToFixture('../data/X.keylayout');
|
||||
const read_unavailable = sut_r.read(inputFilename_unavailable);
|
||||
const converted_unavailable = sut.convert_bound.convert(read_unavailable, inputFilename_unavailable.replace(/\.keylayout$/, '.kmn'));
|
||||
// empty ProcessedData from unavailable file name
|
||||
const inputFilenameUnavailable = makePathToFixture('../data/X.keylayout');
|
||||
const readUnavailable = sutR.read(inputFilenameUnavailable);
|
||||
const convertedUnavailable = sut.convertBound.convert(readUnavailable, inputFilenameUnavailable.replace(/\.keylayout$/, '.kmn'));
|
||||
|
||||
it('writeData_Rules() should return true (no error) if written', async function () {
|
||||
const result = sut_w.writeData_Rules(converted);
|
||||
it('writeDataRules() should return true (no error) if written', async function () {
|
||||
const result = sutW.writeDataRules(converted);
|
||||
assert.isTrue(result.length > 0);
|
||||
});
|
||||
|
||||
it('writeData_Rules() should return false if no inputfile', async function () {
|
||||
const result = sut_w.writeData_Rules(converted_unavailable);
|
||||
it('writeDataRules() should return false if no inputfile', async function () {
|
||||
const result = sutW.writeDataRules(convertedUnavailable);
|
||||
assert.isFalse(result.length > 0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("write_KmnFileHeader() ", function () {
|
||||
describe("writeKmnFileHeader() ", function () {
|
||||
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sut_w = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sutR = new KeylayoutFileReader(compilerTestCallbacks);
|
||||
const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const inputFilename = makePathToFixture('../data/Test.keylayout');
|
||||
const read = sut_r.read(inputFilename);
|
||||
const converted = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
const read = sutR.read(inputFilename);
|
||||
const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
|
||||
|
||||
// empty ProcesData from unavailable file name
|
||||
const inputFilename_unavailable = makePathToFixture('../data/X.keylayout');
|
||||
const read_unavailable = sut_r.read(inputFilename_unavailable);
|
||||
const converted_unavailable = sut.convert_bound.convert(read_unavailable, inputFilename_unavailable.replace(/\.keylayout$/, '.kmn'));
|
||||
// empty ProcessedData from unavailable file name
|
||||
const inputFilenameUnavailable = makePathToFixture('../data/X.keylayout');
|
||||
const readUnavailable = sutR.read(inputFilenameUnavailable);
|
||||
const convertedUnavailable = sut.convertBound.convert(readUnavailable, inputFilenameUnavailable.replace(/\.keylayout$/, '.kmn'));
|
||||
|
||||
// empty ProcesData from empty filename
|
||||
const inputFilename_empty = makePathToFixture('');
|
||||
const read_empty = sut_r.read(inputFilename_empty);
|
||||
const converted_empty = sut.convert_bound.convert(read_empty, inputFilename_empty);
|
||||
// empty ProcessedData from empty filename
|
||||
const inputFilenameEmpty = makePathToFixture('');
|
||||
const readEmpty = sutR.read(inputFilenameEmpty);
|
||||
const convertedEmpty = sut.convertBound.convert(readEmpty, inputFilenameEmpty);
|
||||
|
||||
const out_expected_first: string =
|
||||
const outExpectedFirst: string =
|
||||
"c ..................................................................................................................\n"
|
||||
+ "c ..................................................................................................................\n"
|
||||
+ "c Keyman keyboard generated by kmn-convert version: " + KEYMAN_VERSION.VERSION + "\n"
|
||||
+ "c from Ukelele file: ";
|
||||
|
||||
const out_expected_last: string =
|
||||
const outExpectedLast: string =
|
||||
"\n"
|
||||
+ "c ..................................................................................................................\n"
|
||||
+ "c ..................................................................................................................\n"
|
||||
|
|
@ -106,24 +106,24 @@ describe('KmnFileWriter', function () {
|
|||
+ "group(main) using keys\n\n"
|
||||
+ "\n";
|
||||
|
||||
it(('write_KmnFileHeader should return store text with filename ').padEnd(62, " ") + 'on correct input', async function () {
|
||||
const written_correctName = sut_w.write_KmnFileHeader(converted);
|
||||
assert.equal(written_correctName, (out_expected_first + converted.keylayout_filename + out_expected_last));
|
||||
it(('writeKmnFileHeader should return store text with filename ').padEnd(62, " ") + 'on correct input', async function () {
|
||||
const writtenCorrectName = sutW.writeKmnFileHeader(converted);
|
||||
assert.equal(writtenCorrectName, (outExpectedFirst + converted.keylayoutFilename + outExpectedLast));
|
||||
});
|
||||
|
||||
it(('write_KmnFileHeader should return store text without filename ').padEnd(62, " ") + 'on empty input', async function () {
|
||||
const written_emptyName = sut_w.write_KmnFileHeader(converted_empty);
|
||||
assert.equal(written_emptyName, (out_expected_first + out_expected_last));
|
||||
it(('writeKmnFileHeader should return store text without filename ').padEnd(62, " ") + 'on empty input', async function () {
|
||||
const writtenEmptyName = sutW.writeKmnFileHeader(convertedEmpty);
|
||||
assert.equal(writtenEmptyName, (outExpectedFirst + outExpectedLast));
|
||||
});
|
||||
|
||||
it(('write_KmnFileHeader should return store text without filename ').padEnd(62, " ") + 'on only filename as input', async function () {
|
||||
const written_onlyName = sut_w.write_KmnFileHeader(converted_unavailable);
|
||||
assert.equal(written_onlyName, (out_expected_first + converted_unavailable.keylayout_filename + out_expected_last));
|
||||
it(('writeKmnFileHeader should return store text without filename ').padEnd(62, " ") + 'on only filename as input', async function () {
|
||||
const writtenOnlyName = sutW.writeKmnFileHeader(convertedUnavailable);
|
||||
assert.equal(writtenOnlyName, (outExpectedFirst + convertedUnavailable.keylayoutFilename + outExpectedLast));
|
||||
});
|
||||
});
|
||||
|
||||
describe('reviewRules messages', function () {
|
||||
const sut_w = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
|
||||
[
|
||||
[[new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'UNAVAILABLE', 'K_A', new TextEncoder().encode('A'))],
|
||||
|
|
@ -167,8 +167,8 @@ describe('KmnFileWriter', function () {
|
|||
['c WARNING: unavailable superior rule ( [Y K_Y] > dk(B0) ) : here: ']],
|
||||
|
||||
].forEach(function (values: any, index: number) {
|
||||
it(('rule " ' + values[0][0].rule_type + ' "') + 'should create "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () {
|
||||
const result: string[] = sut_w.reviewRules(values[0], 0);
|
||||
it(('rule " ' + values[0][0].ruleType + ' "') + 'should create "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () {
|
||||
const result: string[] = sutW.reviewRules(values[0], 0);
|
||||
assert.equal(result[0], values[1][0]);
|
||||
assert.equal(result[1], values[2][0]);
|
||||
assert.equal(result[2], values[3][0]);
|
||||
|
|
@ -178,7 +178,7 @@ describe('KmnFileWriter', function () {
|
|||
|
||||
describe('reviewRules messages duplicate and ambiguous', function () {
|
||||
|
||||
const sut_w = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
[
|
||||
//all
|
||||
[[
|
||||
|
|
@ -333,8 +333,8 @@ describe('KmnFileWriter', function () {
|
|||
["c WARNING: duplicate rule: earlier: [CAPS K_C] > 'X' here: "]],
|
||||
|
||||
].forEach(function (values: any, index: number) {
|
||||
it('rule ' + values[0][0].rule_type + ' should create " ' + ' "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () {
|
||||
const result: string[] = sut_w.reviewRules(values[0], 1);
|
||||
it('rule ' + values[0][0].ruleType + ' should create " ' + ' "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () {
|
||||
const result: string[] = sutW.reviewRules(values[0], 1);
|
||||
assert.equal(result[0], values[1][0]);
|
||||
assert.equal(result[1], values[2][0]);
|
||||
assert.equal(result[2], values[3][0]);
|
||||
|
|
@ -343,7 +343,7 @@ describe('KmnFileWriter', function () {
|
|||
});
|
||||
|
||||
describe('reviewRules messages duplicate and ambiguous with Extra warning', function () {
|
||||
const sut_w = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
[[[
|
||||
new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'RALT', 'K_B', new TextEncoder().encode('X')),
|
||||
new Rule("C2", '', '', 0, 0, 'RALT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('Y')),
|
||||
|
|
@ -353,8 +353,8 @@ describe('KmnFileWriter', function () {
|
|||
[''],
|
||||
["c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) ambiguous rule: earlier: [RALT K_B] > 'X' here: PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN ! "]],
|
||||
].forEach(function (values: any, index: number) {
|
||||
it(('rule ' + values[0][0].rule_type + ' should create " ' + ' "') + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () {
|
||||
const result: string[] = sut_w.reviewRules(values[0], 2);
|
||||
it(('rule ' + values[0][0].ruleType + ' should create " ' + ' "') + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () {
|
||||
const result: string[] = sutW.reviewRules(values[0], 2);
|
||||
assert.equal(result[0], values[1][0]);
|
||||
assert.equal(result[1], values[2][0]);
|
||||
assert.equal(result[2], values[3][0]);
|
||||
|
|
@ -363,7 +363,7 @@ describe('KmnFileWriter', function () {
|
|||
});
|
||||
|
||||
describe('write from intermediate data array', function () {
|
||||
const sut_w = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions);
|
||||
[
|
||||
[
|
||||
[ /* see ../data/Test_C0.keylayout */
|
||||
|
|
@ -453,13 +453,13 @@ describe('KmnFileWriter', function () {
|
|||
],
|
||||
].forEach(function (values: any) {
|
||||
it(('an array of Rules should create a set of kmn rules '), async function () {
|
||||
const data: ProcesData = {
|
||||
keylayout_filename: "",
|
||||
kmn_filename: "",
|
||||
arrayOf_Modifiers: [[]],
|
||||
arrayOf_Rules: values[0]
|
||||
const data: ProcessedData = {
|
||||
keylayoutFilename: "",
|
||||
kmnFilename: "",
|
||||
arrayOfModifiers: [[]],
|
||||
arrayOfRules: values[0]
|
||||
};
|
||||
const result1 = sut_w.writeData_Rules(data);
|
||||
const result1 = sutW.writeDataRules(data);
|
||||
assert.isTrue(result1 === values[1][0]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@isaacs/brace-expansion": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
|
||||
"integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz",
|
||||
"integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
|
||||
"dependencies": {
|
||||
"@isaacs/balanced-match": "^4.0.1"
|
||||
},
|
||||
|
|
@ -642,9 +642,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "7.5.6",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.6.tgz",
|
||||
"integrity": "sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==",
|
||||
"version": "7.5.7",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz",
|
||||
"integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==",
|
||||
"dependencies": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
"chownr": "^3.0.0",
|
||||
|
|
@ -723,9 +723,9 @@
|
|||
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="
|
||||
},
|
||||
"@isaacs/brace-expansion": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
|
||||
"integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz",
|
||||
"integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
|
||||
"requires": {
|
||||
"@isaacs/balanced-match": "^4.0.1"
|
||||
}
|
||||
|
|
@ -1166,9 +1166,9 @@
|
|||
}
|
||||
},
|
||||
"tar": {
|
||||
"version": "7.5.6",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.6.tgz",
|
||||
"integrity": "sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==",
|
||||
"version": "7.5.7",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz",
|
||||
"integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==",
|
||||
"requires": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
"chownr": "^3.0.0",
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ https://help.keyman.com/developer/engine/android/latest-version/
|
|||
| KEYMAN_VERSION_ICU | 73.1 |
|
||||
| KEYMAN_VERSION_ISO639_3 | 2024-05-22 |
|
||||
| KEYMAN_VERSION_JAVA | 21 |
|
||||
| KEYMAN_VERSION_LANGTAGS | 2025-02-18 |
|
||||
| KEYMAN_VERSION_LANGTAGS | 2026-02-03 |
|
||||
| KEYMAN_VERSION_LANGUAGE_SUBTAG_REGISTRY | 2025-03-10 |
|
||||
| KEYMAN_VERSION_UNICODE | 17.0.0 |
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
keyman (18.0.246-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Eberhard Beilharz <eb1@sil.org> Wed, 04 Feb 2026 13:48:31 +0100
|
||||
|
||||
keyman (18.0.245-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ Build-Depends:
|
|||
python3-xdg,
|
||||
xserver-xephyr,
|
||||
xvfb,
|
||||
Standards-Version: 4.7.2
|
||||
Standards-Version: 4.7.3
|
||||
Vcs-Git: https://github.com/keymanapp/keyman.git -b beta [linux/debian]
|
||||
Vcs-Browser: https://github.com/keymanapp/keyman/tree/beta/linux/debian
|
||||
Homepage: https://www.keyman.com
|
||||
|
|
|
|||
|
|
@ -6,24 +6,24 @@ Comment: Debian's licensecheck tool uses the term `Expat` for the `MIT` license.
|
|||
`Unicode-3.0` is identified `Unicode-DFS-2016`.
|
||||
|
||||
Files: *
|
||||
Copyright: 2018-2025 SIL Global
|
||||
Copyright: 2018-2026 SIL Global
|
||||
License: Expat
|
||||
|
||||
Files: linux/ibus-keyman/*
|
||||
Copyright: 2004-2025 SIL Global
|
||||
Copyright: 2004-2026 SIL Global
|
||||
License: GPL-2+
|
||||
|
||||
Files: linux/ibus-keyman/src/keymanutil.c
|
||||
linux/ibus-keyman/src/keymanutil.h
|
||||
linux/ibus-keyman/src/kmpdetails.c
|
||||
linux/ibus-keyman/src/kmpdetails.h
|
||||
Copyright: 2009-2025 SIL Global
|
||||
Copyright: 2009-2026 SIL Global
|
||||
License: GPL-2+ or Expat
|
||||
|
||||
Files: linux/ibus-keyman/src/keyman-service.c
|
||||
linux/ibus-keyman/src/keyman-service.h
|
||||
linux/keyman-config/buildtools/help2md
|
||||
Copyright: 2018-2025 SIL Global
|
||||
Copyright: 2018-2026 SIL Global
|
||||
License: GPL-3+
|
||||
|
||||
Files: linux/ibus-keyman/tests/ibusimcontext.c
|
||||
|
|
@ -33,7 +33,7 @@ Copyright: 2008-2010, Peng Huang <shawn.p.huang@gmail.com>
|
|||
2008-2013, Peng Huang <shawn.p.huang@gmail.com>
|
||||
2008-2021, Red Hat, Inc.
|
||||
2015-2021, Takao Fujiwara <takao.fujiwara1@gmail.com>
|
||||
2021-2025, SIL Global
|
||||
2021-2026, SIL Global
|
||||
License: LGPL-2.1+
|
||||
|
||||
Files: linux/keyman-config/buildtools/help2man
|
||||
|
|
@ -43,7 +43,7 @@ License: GPL-3+
|
|||
Files: debian/com.keyman.config.appdata.xml
|
||||
debian/com.keyman.ibus_keyman.metainfo.xml
|
||||
Copyright: 2019 Daniel Glassey <wdg@debian.org>
|
||||
2022-2025 SIL Global
|
||||
2022-2026 SIL Global
|
||||
License: Expat
|
||||
|
||||
Files: resources/standards-data/ldml-keyboards/*
|
||||
|
|
|
|||
|
|
@ -74,14 +74,18 @@ class ViewInstalledWindowBase(Gtk.Window):
|
|||
filter_text.set_name(_("KMP files"))
|
||||
filter_text.add_pattern("*.kmp")
|
||||
dlg.add_filter(filter_text)
|
||||
response = dlg.run()
|
||||
if response != Gtk.ResponseType.OK:
|
||||
dlg.destroy()
|
||||
return
|
||||
while True:
|
||||
response = dlg.run()
|
||||
if response != Gtk.ResponseType.OK:
|
||||
dlg.destroy()
|
||||
return
|
||||
|
||||
file = dlg.get_filename()
|
||||
dlg.destroy()
|
||||
self.restart(self.install_file(file))
|
||||
file = dlg.get_filename()
|
||||
if file and os.path.isfile(file) and os.path.splitext(file)[1] == '.kmp':
|
||||
dlg.destroy()
|
||||
self.restart(self.install_file(file))
|
||||
return
|
||||
# Loop until we have a valid file or the user cancels the dialog
|
||||
|
||||
def install_file(self, kmpfile, language=None):
|
||||
installDlg = InstallKmpWindow(kmpfile, viewkmp=self, language=language)
|
||||
|
|
|
|||
|
|
@ -15,14 +15,14 @@ mkdir -p builddebs
|
|||
|
||||
# make the source packages
|
||||
cd builddebs
|
||||
vers=$(ls ../dist/keyman_*.orig.tar.gz)
|
||||
vers=$(ls ../dist/keyman_*.orig.tar.xz)
|
||||
#echo "vers1:${vers}"
|
||||
vers=${vers##*_}
|
||||
#echo "vers2:${vers}"
|
||||
vers=${vers%*.orig.tar.gz}
|
||||
vers=${vers%*.orig.tar.xz}
|
||||
#echo "vers3:${vers}"
|
||||
cp -a "../dist/keyman_${vers}.orig.tar.gz" .
|
||||
tar xfz "keyman_${vers}.orig.tar.gz"
|
||||
cp -a "../dist/keyman_${vers}.orig.tar.xz" .
|
||||
tar xfJ "keyman_${vers}.orig.tar.xz"
|
||||
cp -a ../../debian "keyman-${vers}"
|
||||
cd "keyman-${vers}"
|
||||
dch -v "${vers}-1" "local build"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# and put them in dist/
|
||||
|
||||
# parameters: ./dist.sh [origdist] [proj]
|
||||
# origdist = create Debian orig.tar.gz
|
||||
# origdist = create Debian orig.tar.xz
|
||||
# proj = only make tarball for this project
|
||||
|
||||
set -e
|
||||
|
|
@ -39,8 +39,9 @@ dch keyman --newversion "${KEYMAN_VERSION}" --force-bad-version --nomultimaint
|
|||
|
||||
# Create the tarball
|
||||
|
||||
# files and folders to include in the tarball
|
||||
# shellcheck disable=2034 # to_exclude appears to be unused
|
||||
# We always include these files which are the minimum files and
|
||||
# folder required for Ubuntu/Debian packaging
|
||||
# shellcheck disable=2034 # to_include appears to be unused
|
||||
to_include=(
|
||||
common/build.sh \
|
||||
common/cpp \
|
||||
|
|
@ -60,18 +61,61 @@ to_include=(
|
|||
|
||||
# files and subfolders to exclude from paths included in 'to_include',
|
||||
# i.e. the exceptions to 'to_include'.
|
||||
|
||||
# shellcheck disable=2034 # to_exclude appears to be unused
|
||||
to_exclude=(
|
||||
build \
|
||||
common/test/keyboards/baseline/kmcomp-*.zip \
|
||||
core/build \
|
||||
linux/build \
|
||||
linux/builddebs \
|
||||
linux/docs/help \
|
||||
linux/keyman-config/keyman_config/version.py \
|
||||
linux/keyman-config/buildtools/build-langtags.py \
|
||||
linux/keyman-system-service/build
|
||||
)
|
||||
|
||||
if [[ -z "${create_origdist+x}" ]]; then
|
||||
# If we build a full source tarball we include additional files
|
||||
# so that it's possible to run `${KEYMAN_ROOT}/build.sh` on Linux
|
||||
|
||||
# shellcheck disable=2034 # to_include appears to be unused
|
||||
to_include+=(
|
||||
common/tools/hextobin \
|
||||
common/web/keyman-version \
|
||||
common/web/langtags \
|
||||
common/web/types \
|
||||
common/windows/cpp \
|
||||
common/windows/include \
|
||||
developer/src/common/include \
|
||||
developer/src/common/web \
|
||||
developer/src/ext/json \
|
||||
developer/src/kmc \
|
||||
developer/src/kmc-analyze \
|
||||
developer/src/kmc-copy \
|
||||
developer/src/kmc-generate \
|
||||
developer/src/kmc-keyboard-info \
|
||||
developer/src/kmc-kmn \
|
||||
developer/src/kmc-ldml \
|
||||
developer/src/kmc-model \
|
||||
developer/src/kmc-model-info \
|
||||
developer/src/kmc-package \
|
||||
developer/src/kmcmplib \
|
||||
docs/minimum-versions.md.in
|
||||
resources/build \
|
||||
resources/standards-data \
|
||||
)
|
||||
|
||||
# additional files and subfolders to exclude from paths included in 'to_include',
|
||||
# i.e. the exceptions to 'to_include'.
|
||||
# shellcheck disable=2034 # to_exclude appears to be unused
|
||||
to_exclude+=(
|
||||
*.exe \
|
||||
resources/build/history \
|
||||
resources/build/l10n \
|
||||
resources/build/mac \
|
||||
resources/build/win \
|
||||
resources/build/*.lua \
|
||||
)
|
||||
fi
|
||||
|
||||
# array to store list of --tar-ignore parameters generated from to_include and to_exclude.
|
||||
ignored_files=()
|
||||
|
||||
|
|
@ -101,19 +145,19 @@ dpkg-source \
|
|||
\
|
||||
"${ignored_files[@]}" \
|
||||
\
|
||||
-Zgzip -b .
|
||||
-Zxz -b .
|
||||
|
||||
mv ../keyman_"${KEYMAN_VERSION}".tar.gz linux/dist/keyman-"${KEYMAN_VERSION}".tar.gz
|
||||
mv ../keyman_"${KEYMAN_VERSION}".tar.xz linux/dist/keyman-"${KEYMAN_VERSION}".tar.xz
|
||||
echo "3.0 (quilt)" > debian/source/format
|
||||
cd "${BASEDIR}"
|
||||
|
||||
# create orig.tar.gz
|
||||
# create orig.tar.xz
|
||||
if [[ ! -z "${create_origdist+x}" ]]; then
|
||||
cd dist
|
||||
cd "${KEYMAN_ROOT}/linux/dist"
|
||||
pkgvers="keyman-${KEYMAN_VERSION}"
|
||||
tar xfz keyman-"${KEYMAN_VERSION}".tar.gz
|
||||
tar xfJ keyman-"${KEYMAN_VERSION}".tar.xz
|
||||
mv -v keyman "${pkgvers}" 2>/dev/null || mv -v "$(find . -mindepth 1 -maxdepth 1 -type d)" "${pkgvers}"
|
||||
tar cfz "keyman_${KEYMAN_VERSION}.orig.tar.gz" "${pkgvers}"
|
||||
rm "keyman-${KEYMAN_VERSION}.tar.gz"
|
||||
tar cfJ "keyman_${KEYMAN_VERSION}.orig.tar.xz" "${pkgvers}"
|
||||
rm "keyman-${KEYMAN_VERSION}.tar.xz"
|
||||
rm -rf "${pkgvers}"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ function downloadSource() {
|
|||
uscan || (echo "ERROR: No new version available for ${proj}" >&2 && exit 1)
|
||||
cd ..
|
||||
mv "${proj}-${version}" "${BASEDIR}/${packageDir}"
|
||||
mv "${proj}_${version}.orig.tar.gz" "${BASEDIR}/${packageDir}"
|
||||
mv "${proj}-${version}.tar.gz" "${BASEDIR}/${packageDir}"
|
||||
mv "${proj}_${version}.orig.tar.xz" "${BASEDIR}/${packageDir}"
|
||||
mv "${proj}-${version}.tar.xz" "${BASEDIR}/${packageDir}"
|
||||
mv "${proj}"*.asc "${BASEDIR}/${packageDir}"
|
||||
rm "${proj}"*.debian.tar.xz
|
||||
cd "${BASEDIR}/${packageDir}" || exit
|
||||
|
|
@ -91,78 +91,135 @@ function generate_tar_ignore_list() {
|
|||
local list_var="$4"
|
||||
local prefix="$5"
|
||||
local includes_array="${includes_var}[@]"
|
||||
# shellcheck disable=SC2034
|
||||
local includes=("${!includes_array}")
|
||||
local excludes_array="${excludes_var}[@]"
|
||||
local excludes=("${!excludes_array}")
|
||||
local dir all_dirs found_match inc
|
||||
|
||||
mapfile -t all_dirs < <(find "${directory}" -mindepth 1 -maxdepth 1 -type d | sort)
|
||||
for dir in "${all_dirs[@]}"; do
|
||||
found_match=false
|
||||
for inc in "${includes[@]}"; do
|
||||
if [[ "./${inc}" =~ ^${dir} ]]; then
|
||||
found_match=true
|
||||
if [[ "./${inc}" != "${dir}" ]]; then
|
||||
# check subdirectories
|
||||
generate_tar_ignore_list "${dir}" "${includes_var}" "${excludes_var}" "${list_var}" "${prefix}"
|
||||
fi
|
||||
# check if files/subdir in $dir are in excludes list
|
||||
_generate_excludes_for_dir "${dir}" "${includes_var}" "${excludes_var}" "${list_var}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if ! ${found_match}; then
|
||||
_add_to_list "${list_var}" "${dir}"
|
||||
# Loop through excludes and put all without path in single_excludes
|
||||
local single_excludes=()
|
||||
for item in "${excludes[@]}"; do
|
||||
if [[ ${item} != */* ]]; then
|
||||
single_excludes+=("${item}")
|
||||
fi
|
||||
done
|
||||
|
||||
local ignore_list=()
|
||||
_process_directory "${directory}" false
|
||||
|
||||
for item in "${ignore_list[@]}"; do
|
||||
eval "${list_var}+=(\"--tar-ignore=${item}\")"
|
||||
done
|
||||
}
|
||||
|
||||
function _generate_excludes_for_dir() {
|
||||
function _process_directory() {
|
||||
local directory="$1"
|
||||
local includes_var="$2"
|
||||
local excludes_var="$3"
|
||||
local list_var="$4"
|
||||
local includes_array="${includes_var}[@]"
|
||||
local includes=("${!includes_array}")
|
||||
local excludes_array="${excludes_var}[@]"
|
||||
local excludes=("${!excludes_array}")
|
||||
local file all_files excluded included is_match
|
||||
local isParentIncluded="$2"
|
||||
local all_items item
|
||||
|
||||
mapfile -t all_files < <(find "${directory}" -mindepth 1 -maxdepth 1 | sort)
|
||||
is_match=false
|
||||
for file in "${all_files[@]}"; do
|
||||
for included in "${includes[@]}"; do
|
||||
if [[ "${file}" == ./${included} ]]; then
|
||||
is_match=true
|
||||
break
|
||||
mapfile -t all_items < <(find "${directory}" -mindepth 1 -maxdepth 1 | sort)
|
||||
for item in "${all_items[@]}"; do
|
||||
debug "Checking item: ${item}"
|
||||
if _is_exact_match "includes" "${item}"; then
|
||||
debug " Including (full match): ${item}"
|
||||
if [[ -d "${item}" ]]; then
|
||||
_process_directory "${item}" true
|
||||
fi
|
||||
done
|
||||
if ${is_match} ; then
|
||||
if [[ "${file}" != ./${included} ]] && [[ -f "${file}" ]]; then
|
||||
_add_to_list "${list_var}" "${file}"
|
||||
elif _starts_with "includes" "${item}"; then
|
||||
debug " Including (partial match): ${item}"
|
||||
if [[ -d "${item}" ]]; then
|
||||
_process_directory "${item}" "${isParentIncluded}"
|
||||
fi
|
||||
elif _is_exact_match "excludes" "${item}"; then
|
||||
debug " Excluding (full match): ${item}"
|
||||
_add_to_list "${item}"
|
||||
elif _ends_with "single_excludes" "${item}" || _is_wildcard_match "single_excludes" "${item}"; then
|
||||
debug " Excluding (single exclude): ${item}"
|
||||
_add_to_list "${item}"
|
||||
elif [[ "${isParentIncluded}" == "false" ]]; then
|
||||
debug " Excluding (not included): ${item}"
|
||||
_add_to_list "${item}"
|
||||
else
|
||||
for excluded in "${excludes[@]}"; do
|
||||
if [[ "${file}" == ./${excluded} ]]; then
|
||||
_add_to_list "${list_var}" "${file}"
|
||||
break
|
||||
elif [[ "./${excluded}" =~ ^${file} ]]; then
|
||||
# check subdirectories
|
||||
_generate_excludes_for_dir "${file}" "${includes_var}" "${excludes_var}" "${list_var}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
debug " Including (parent included): ${item}"
|
||||
if [[ -d "${item}" ]]; then
|
||||
_process_directory "${item}" "${isParentIncluded}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function _add_to_list() {
|
||||
local list_var="$1"
|
||||
local filename="$2"
|
||||
|
||||
# Note: the files end up in subdirectories under `keyman` (or rather
|
||||
# the directory name of $KEYMAN_ROOT), so we can
|
||||
# include that when matching files and directories to ignore.
|
||||
# shellcheck disable=SC2154
|
||||
eval "${list_var}+=(\"--tar-ignore=${prefix}/${filename#./}\")"
|
||||
local item="$1"
|
||||
ignore_list+=("${prefix}/${item#./}")
|
||||
}
|
||||
|
||||
# Returns true if one of the values in the $1 array equals ${file} ($2)
|
||||
# Example: will return true for array=(path1/path2) file=./path1/path2
|
||||
function _is_exact_match() {
|
||||
local array_var="$1"
|
||||
local file="$2"
|
||||
local array_name="${array_var}[@]"
|
||||
local haystack=("${!array_name}")
|
||||
local item
|
||||
for item in "${haystack[@]}"; do
|
||||
if [[ "./${item#./}" == "${file}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Returns true if one of the values in the $1 array starts with ${file} ($2)
|
||||
# Example: will return true for array=(path1/path2) file=./path1
|
||||
function _starts_with() {
|
||||
local array_var="$1"
|
||||
local file="$2"
|
||||
local array_name="${array_var}[@]"
|
||||
local array_values=("${!array_name}")
|
||||
local array_item
|
||||
for array_item in "${array_values[@]}"; do
|
||||
if [[ "./${array_item#./}" == ${file}* ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Returns true if ${file} ($2) ends with one of the values in the $1 array
|
||||
# Example: will return true for array=(path2) file=./path1/path2
|
||||
function _ends_with() {
|
||||
local array_var="$1"
|
||||
local file="$2"
|
||||
local array_name="${array_var}[@]"
|
||||
local array_values=("${!array_name}")
|
||||
local array_item
|
||||
for array_item in "${array_values[@]}"; do
|
||||
if [[ "${file}" == */${array_item#./} ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Returns true if ${file} ($2) matches one of the values of the $1 array.
|
||||
# These values may contain wildcards.
|
||||
# Example: will return true for array=(*.sh) file=./path1/build.sh
|
||||
function _is_wildcard_match() {
|
||||
local array_var="$1"
|
||||
local file="$2"
|
||||
local array_name="${array_var}[@]"
|
||||
local array_values=("${!array_name}")
|
||||
local array_item
|
||||
for array_item in "${array_values[@]}"; do
|
||||
array_item=${array_item/./\\.}
|
||||
if [[ "${file}" =~ /${array_item/\*/.\*}$ ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
function debug() {
|
||||
# echo "$@"
|
||||
return 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,61 +16,105 @@ function setup_file() {
|
|||
# Create directory structure for testing
|
||||
# /
|
||||
# /subdir1
|
||||
# /build/foo
|
||||
# /build.sh
|
||||
# /README.md
|
||||
# /path1
|
||||
# /abc.build
|
||||
# /build/foo
|
||||
# /build.sh
|
||||
# /README.md
|
||||
# /x/z.txt
|
||||
# /xy/z.txt
|
||||
# /path2
|
||||
# /build/foo
|
||||
# /build.sh
|
||||
# /path3
|
||||
# /build/foo
|
||||
# /build.sh
|
||||
# /subdir2
|
||||
# /build/foo
|
||||
# /build.sh
|
||||
# /path1
|
||||
# /build/foo
|
||||
# /subdir3
|
||||
# /build/foo
|
||||
# /build.sh
|
||||
# /path1
|
||||
# /build/foo
|
||||
# /path2
|
||||
# /build/foo
|
||||
# /path3
|
||||
# /subdir4
|
||||
# /build/foo
|
||||
# /build.sh
|
||||
# /path1
|
||||
# /build.sh
|
||||
# /path2
|
||||
# /subpath1
|
||||
# /build/foo
|
||||
# /build.sh
|
||||
# /subpath2
|
||||
# /build/foo
|
||||
# /build.sh
|
||||
# /path3
|
||||
# /build.sh
|
||||
# /build.sh
|
||||
# subdir1/path2, subdir2, subdir4/path1, subdir4/path2/subpath1,
|
||||
# and subdir4/path3 will be ignored
|
||||
mkdir -p "${temp_dir}/subdir1/path1" # include
|
||||
touch "${temp_dir}/subdir1/build.sh"
|
||||
# all build/ directories will be ignored with the exception of
|
||||
# subdir3/build.
|
||||
mkdir -p "${temp_dir}/subdir1/build" # exclude
|
||||
touch "${temp_dir}/subdir1/build/foo" # exclude
|
||||
mkdir -p "${temp_dir}/subdir1/path1/build"
|
||||
touch "${temp_dir}/subdir1/path1/build/foo" # exclude
|
||||
mkdir -p "${temp_dir}/subdir1/path1/x"
|
||||
touch "${temp_dir}/subdir1/path1/x/z.txt"
|
||||
mkdir -p "${temp_dir}/subdir1/path1/xy"
|
||||
touch "${temp_dir}/subdir1/path1/xy/z.txt"
|
||||
touch "${temp_dir}/subdir1/build.sh" # include
|
||||
touch "${temp_dir}/subdir1/README.md" # exclude
|
||||
touch "${temp_dir}/subdir1/path1/abc.build"
|
||||
touch "${temp_dir}/subdir1/path1/build.sh" # include
|
||||
touch "${temp_dir}/subdir1/path1/README.md" # exclude
|
||||
mkdir -p "${temp_dir}/subdir1/path2" # exclude
|
||||
touch "${temp_dir}/subdir1/path2/build.sh"
|
||||
mkdir -p "${temp_dir}/subdir1/path3" # include
|
||||
touch "${temp_dir}/subdir1/path3/build.sh"
|
||||
mkdir -p "${temp_dir}/subdir2/path1" # exclude
|
||||
mkdir -p "${temp_dir}/subdir1/path2/build"
|
||||
touch "${temp_dir}/subdir1/path2/build/foo" # exclude
|
||||
touch "${temp_dir}/subdir1/path2/build.sh" # exclude
|
||||
mkdir -p "${temp_dir}/subdir1/path3/build"
|
||||
touch "${temp_dir}/subdir1/path2/build/foo" # exclude
|
||||
touch "${temp_dir}/subdir1/path3/build.sh" # include
|
||||
mkdir -p "${temp_dir}/subdir2/build" # exclude
|
||||
touch "${temp_dir}/subdir2/build/foo" # exclude
|
||||
mkdir -p "${temp_dir}/subdir2/path1/build" # exclude
|
||||
touch "${temp_dir}/subdir2/path1/build/foo" # exclude
|
||||
touch "${temp_dir}/subdir2/build.sh"
|
||||
mkdir -p "${temp_dir}/subdir3/build" # include
|
||||
touch "${temp_dir}/subdir3/build/foo" # include
|
||||
mkdir -p "${temp_dir}/subdir3/path1" # include
|
||||
touch "${temp_dir}/subdir3/build.sh"
|
||||
mkdir -p "${temp_dir}/subdir3/path1/build" # exclude
|
||||
touch "${temp_dir}/subdir3/path1/build/foo" # exclude
|
||||
mkdir -p "${temp_dir}/subdir3/path2" # include
|
||||
mkdir -p "${temp_dir}/subdir3/path2/build" # exclude
|
||||
touch "${temp_dir}/subdir3/path2/build/foo" # exclude
|
||||
mkdir -p "${temp_dir}/subdir3/path3" # include
|
||||
mkdir -p "${temp_dir}/subdir4/build" # exclude
|
||||
touch "${temp_dir}/subdir4/build/foo" # exclude
|
||||
mkdir -p "${temp_dir}/subdir4/path1" # exclude
|
||||
touch "${temp_dir}/subdir4/build.sh"
|
||||
touch "${temp_dir}/subdir4/path1/build.sh"
|
||||
mkdir -p "${temp_dir}/subdir4/path2/subpath1" # exclude
|
||||
touch "${temp_dir}/subdir4/path2/subpath1/build.sh"
|
||||
mkdir -p "${temp_dir}/subdir4/path2/subpath1/build" # exclude
|
||||
touch "${temp_dir}/subdir4/path2/subpath1/build/foo" # exclude
|
||||
mkdir -p "${temp_dir}/subdir4/path2/subpath2" # include
|
||||
touch "${temp_dir}/subdir4/path2/subpath2/build.sh"
|
||||
mkdir -p "${temp_dir}/subdir4/path2/subpath2/build" # exclude
|
||||
touch "${temp_dir}/subdir4/path2/subpath2/build/foo" # exclude
|
||||
mkdir -p "${temp_dir}/subdir4/path3" # exclude
|
||||
touch "${temp_dir}/subdir4/path3/build.sh"
|
||||
touch "${temp_dir}/subdir4/path3/other.txt"
|
||||
touch "${temp_dir}/build.sh"
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
|
|
@ -89,9 +133,14 @@ function test__generate_tar_ignore_list__basic() {
|
|||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=test1/build.sh
|
||||
--tar-ignore=test1/subdir1/build
|
||||
--tar-ignore=test1/subdir1/build.sh
|
||||
--tar-ignore=test1/subdir1/path2
|
||||
--tar-ignore=test1/subdir1/README.md
|
||||
--tar-ignore=test1/subdir2
|
||||
--tar-ignore=test1/subdir4/build
|
||||
--tar-ignore=test1/subdir4/build.sh
|
||||
--tar-ignore=test1/subdir4/path1
|
||||
--tar-ignore=test1/subdir4/path2/subpath1
|
||||
--tar-ignore=test1/subdir4/path3
|
||||
|
|
@ -113,6 +162,9 @@ function test__generate_tar_ignore_list__path_wildcard_in_exclude() {
|
|||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=foo/build.sh # not in include
|
||||
--tar-ignore=foo/subdir1/build # not in include
|
||||
--tar-ignore=foo/subdir1/build.sh # not in include
|
||||
--tar-ignore=foo/subdir1/path1/README.md # in exclude
|
||||
--tar-ignore=foo/subdir1/path2 # not in include
|
||||
--tar-ignore=foo/subdir1/README.md # not in include
|
||||
|
|
@ -136,10 +188,12 @@ function test__generate_tar_ignore_list__file_wildcard_in_exclude() {
|
|||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=keyman/build.sh # not in include
|
||||
--tar-ignore=keyman/subdir1/build # not in include
|
||||
--tar-ignore=keyman/subdir1/build.sh # not in include
|
||||
--tar-ignore=keyman/subdir1/path1/build.sh # in exclude
|
||||
--tar-ignore=keyman/subdir1/path2 # not in include
|
||||
--tar-ignore=keyman/subdir1/path3/build.sh # in exclude
|
||||
--tar-ignore=keyman/subdir1/build.sh # not in include
|
||||
--tar-ignore=keyman/subdir1/README.md # not in include
|
||||
--tar-ignore=keyman/subdir2 # not in include
|
||||
--tar-ignore=keyman/subdir3/build.sh # in exclude
|
||||
|
|
@ -162,13 +216,17 @@ function test__generate_tar_ignore_list__file_wildcard_in_include() {
|
|||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=xyz/build.sh # not in include
|
||||
--tar-ignore=xyz/subdir1/build # not in include
|
||||
--tar-ignore=xyz/subdir1/build.sh # not in include
|
||||
--tar-ignore=xyz/subdir1/path2 # not in include
|
||||
--tar-ignore=xyz/subdir1/README.md # in exclude
|
||||
--tar-ignore=xyz/subdir2 # not in include
|
||||
--tar-ignore=xyz/subdir4/build # not in include
|
||||
--tar-ignore=xyz/subdir4/build.sh # not in include
|
||||
--tar-ignore=xyz/subdir4/path1 # not in include
|
||||
--tar-ignore=xyz/subdir4/path2 # not in include
|
||||
--tar-ignore=xyz/subdir4/path3/other.txt # not in include
|
||||
--tar-ignore=xyz/subdir4/path2/subpath1 # not necessary, but in exclude
|
||||
)
|
||||
|
||||
assert-equal "${ignored_files[*]}" "${expected[*]}"
|
||||
|
|
@ -187,9 +245,14 @@ function test__generate_tar_ignore_list__path_wildcard_in_include() {
|
|||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=bar/build.sh # not in include
|
||||
--tar-ignore=bar/subdir1/build # not in include
|
||||
--tar-ignore=bar/subdir1/build.sh # not in include
|
||||
--tar-ignore=bar/subdir1/path2 # not in include
|
||||
--tar-ignore=bar/subdir1/README.md # not in include
|
||||
--tar-ignore=bar/subdir2 # not in include
|
||||
--tar-ignore=bar/subdir4/build # not in include
|
||||
--tar-ignore=bar/subdir4/build.sh # not in include
|
||||
--tar-ignore=bar/subdir4/path1 # not in include
|
||||
--tar-ignore=bar/subdir4/path2/subpath1 # not in include
|
||||
--tar-ignore=bar/subdir4/path3 # not in include
|
||||
|
|
@ -210,15 +273,370 @@ function test__generate_tar_ignore_list__exclude_subsubdir() {
|
|||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=baz/subdir1
|
||||
--tar-ignore=baz/subdir2
|
||||
--tar-ignore=baz/subdir3
|
||||
--tar-ignore=baz/subdir4/path2/subpath2
|
||||
--tar-ignore=baz/build.sh # not in include
|
||||
--tar-ignore=baz/subdir1 # not in include
|
||||
--tar-ignore=baz/subdir2 # not in include
|
||||
--tar-ignore=baz/subdir3 # not in include
|
||||
--tar-ignore=baz/subdir4/path2/subpath2 # in exclude
|
||||
)
|
||||
|
||||
assert-equal "${ignored_files[*]}" "${expected[*]}"
|
||||
}
|
||||
|
||||
function test__generate_tar_ignore_list__exclude_build_Dirs() {
|
||||
to_include=(subdir1/path1 subdir1/path3 subdir3 subdir3/build subdir4/path2)
|
||||
to_exclude=(subdir1/README.md subdir4/path2/subpath1 subdir4/path2/subpath3 build)
|
||||
|
||||
cd "${temp_dir}"
|
||||
ignored_files=()
|
||||
|
||||
# Execute
|
||||
generate_tar_ignore_list "./" to_include to_exclude ignored_files wildcard
|
||||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=wildcard/build.sh # not in include
|
||||
--tar-ignore=wildcard/subdir1/build # in exclude
|
||||
--tar-ignore=wildcard/subdir1/build.sh # not in include
|
||||
--tar-ignore=wildcard/subdir1/path1/build # in exclude
|
||||
--tar-ignore=wildcard/subdir1/path2 # not in include
|
||||
--tar-ignore=wildcard/subdir1/path3/build # in exclude
|
||||
--tar-ignore=wildcard/subdir1/README.md # in exclude
|
||||
--tar-ignore=wildcard/subdir2 # not in include
|
||||
--tar-ignore=wildcard/subdir3/path1/build # in exclude
|
||||
--tar-ignore=wildcard/subdir3/path2/build # in exclude
|
||||
--tar-ignore=wildcard/subdir4/build # in exclude
|
||||
--tar-ignore=wildcard/subdir4/build.sh # not in include
|
||||
--tar-ignore=wildcard/subdir4/path1 # not in include
|
||||
--tar-ignore=wildcard/subdir4/path2/subpath1 # in exclude
|
||||
--tar-ignore=wildcard/subdir4/path2/subpath2/build # in exclude
|
||||
--tar-ignore=wildcard/subdir4/path3 # not in include
|
||||
)
|
||||
|
||||
assert-equal "${ignored_files[*]}" "${expected[*]}"
|
||||
}
|
||||
|
||||
function test__generate_tar_ignore_list__exclude_xy() {
|
||||
to_include=(subdir1 subdir2 subdir3 subdir4)
|
||||
to_exclude=(xy)
|
||||
|
||||
cd "${temp_dir}"
|
||||
ignored_files=()
|
||||
|
||||
# Execute
|
||||
generate_tar_ignore_list "./" to_include to_exclude ignored_files wildcard
|
||||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=wildcard/build.sh # not in include
|
||||
--tar-ignore=wildcard/subdir1/path1/xy # in exclude
|
||||
)
|
||||
|
||||
assert-equal "${ignored_files[*]}" "${expected[*]}"
|
||||
}
|
||||
|
||||
function test__generate_tar_ignore_list__exclude_x_doesnot_exclude_xy() {
|
||||
to_include=(subdir1 subdir2 subdir3 subdir4)
|
||||
to_exclude=(x)
|
||||
|
||||
cd "${temp_dir}"
|
||||
ignored_files=()
|
||||
|
||||
# Execute
|
||||
generate_tar_ignore_list "./" to_include to_exclude ignored_files wildcard
|
||||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=wildcard/build.sh # not in include
|
||||
--tar-ignore=wildcard/subdir1/path1/x # in exclude
|
||||
)
|
||||
|
||||
assert-equal "${ignored_files[*]}" "${expected[*]}"
|
||||
}
|
||||
|
||||
function test__generate_tar_ignore_list__can_include_toplevel_files() {
|
||||
to_include=(subdir1 subdir3 ./build.sh)
|
||||
to_exclude=(*.sh)
|
||||
|
||||
cd "${temp_dir}"
|
||||
ignored_files=()
|
||||
|
||||
# Execute
|
||||
generate_tar_ignore_list "./" to_include to_exclude ignored_files top
|
||||
|
||||
# Verify
|
||||
expected=(
|
||||
--tar-ignore=top/subdir1/build.sh # in exclude
|
||||
--tar-ignore=top/subdir1/path1/build.sh # in exclude
|
||||
--tar-ignore=top/subdir1/path2/build.sh # in exclude
|
||||
--tar-ignore=top/subdir1/path3/build.sh # in exclude
|
||||
--tar-ignore=top/subdir2 # not in include
|
||||
--tar-ignore=top/subdir3/build.sh # in exclude
|
||||
--tar-ignore=top/subdir4 # not in include
|
||||
)
|
||||
|
||||
assert-equal "${ignored_files[*]}" "${expected[*]}"
|
||||
}
|
||||
|
||||
# Tests for _starts_with function
|
||||
function test__starts_with__match_parent() {
|
||||
# Setup
|
||||
includes=(subdir1/path1 subdir3)
|
||||
|
||||
# Verify
|
||||
assert-true _starts_with includes ./subdir1
|
||||
}
|
||||
|
||||
function test__starts_with__exact_match() {
|
||||
# Setup
|
||||
includes=(subdir1/path1 subdir3)
|
||||
|
||||
# Verify
|
||||
assert-true _starts_with includes ./subdir1/path1
|
||||
}
|
||||
|
||||
function test__starts_with__exact_match_localdir() {
|
||||
# Setup
|
||||
includes=(./subdir1/path1 ./subdir3)
|
||||
|
||||
# Verify
|
||||
assert-true _starts_with includes ./subdir1/path1
|
||||
}
|
||||
|
||||
function test__starts_with__no_match() {
|
||||
# Setup
|
||||
includes=(subdir1/path1 subdir3)
|
||||
|
||||
# Verify
|
||||
assert-false _starts_with includes ./subdir2
|
||||
}
|
||||
|
||||
function test__starts_with__normalized_paths() {
|
||||
# Setup
|
||||
includes=(path1 path2)
|
||||
|
||||
# Verify
|
||||
assert-true _starts_with includes ./path1
|
||||
}
|
||||
|
||||
function test__starts_with__subdir() {
|
||||
# Setup
|
||||
includes=(path1 path2)
|
||||
|
||||
# Verify
|
||||
assert-false _starts_with includes ./path1/subdir
|
||||
}
|
||||
|
||||
function test__starts_with__no_match_different_name() {
|
||||
# Setup
|
||||
includes=(path1 path2)
|
||||
|
||||
# Verify
|
||||
assert-false _starts_with includes ./path3
|
||||
}
|
||||
|
||||
# Tests for _ends_with function
|
||||
function test__ends_with__exact_filename_first() {
|
||||
# Setup
|
||||
local array=(README.md test.txt)
|
||||
|
||||
# Verify
|
||||
assert-true _ends_with array ./subdir/README.md
|
||||
}
|
||||
|
||||
function test__ends_with__exact_filename_second() {
|
||||
# Setup
|
||||
local array=(README.md test.txt)
|
||||
|
||||
# Verify
|
||||
assert-true _ends_with array ./path/to/test.txt
|
||||
}
|
||||
|
||||
function test__ends_with__not_matching_similar_extension() {
|
||||
# Setup
|
||||
local array=(README.md test.txt)
|
||||
|
||||
# Verify
|
||||
assert-false _ends_with array ./README.md.bak
|
||||
}
|
||||
|
||||
function test__ends_with__no_match_other_filename() {
|
||||
# Setup
|
||||
local array=(README.md test.txt)
|
||||
|
||||
# Verify
|
||||
assert-false _ends_with array ./other.txt
|
||||
}
|
||||
|
||||
# Tests for _is_exact_match function
|
||||
function test__is_exact_match__full_path_first() {
|
||||
# Setup
|
||||
includes=(./subdir1/path1 subdir3)
|
||||
|
||||
# Verify
|
||||
assert-true _is_exact_match includes ./subdir1/path1
|
||||
}
|
||||
|
||||
function test__is_exact_match__full_path_second() {
|
||||
# Setup
|
||||
includes=(./subdir1/path1 subdir3)
|
||||
|
||||
# Verify
|
||||
assert-true _is_exact_match includes ./subdir3
|
||||
}
|
||||
|
||||
function test__is_exact_match__partial_path_no_match() {
|
||||
# Setup
|
||||
includes=(./subdir1/path1 subdir3)
|
||||
|
||||
# Verify
|
||||
assert-false _is_exact_match includes ./subdir1
|
||||
}
|
||||
|
||||
function test__is_exact_match__sibling_path_no_match() {
|
||||
# Setup
|
||||
includes=(./subdir1/path1 subdir3)
|
||||
|
||||
# Verify
|
||||
assert-false _is_exact_match includes ./subdir1/path2
|
||||
}
|
||||
|
||||
function test__is_exact_match__normalized_paths_first() {
|
||||
# Setup
|
||||
includes=(subdir1 subdir2)
|
||||
|
||||
# Verify
|
||||
assert-true _is_exact_match includes ./subdir1
|
||||
}
|
||||
|
||||
function test__is_exact_match__normalized_paths_second() {
|
||||
# Setup
|
||||
includes=(subdir1 subdir2)
|
||||
|
||||
# Verify
|
||||
assert-true _is_exact_match includes ./subdir2
|
||||
}
|
||||
|
||||
function test__is_exact_match__empty_array() {
|
||||
# Setup
|
||||
includes=()
|
||||
|
||||
# Verify
|
||||
assert-false _is_exact_match includes ./anything
|
||||
}
|
||||
|
||||
# Tests for _is_wildcard_match function
|
||||
function test__is_wildcard_match__file() {
|
||||
# Setup
|
||||
local array=(sh)
|
||||
|
||||
# Verify
|
||||
assert-true _is_wildcard_match array ./config/sh
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__dot_file() {
|
||||
# Setup
|
||||
local array=(sh)
|
||||
|
||||
# Verify
|
||||
assert-false _is_wildcard_match array ./config/.sh
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__dot_files_nested() {
|
||||
# Setup
|
||||
local array=(.sh)
|
||||
|
||||
# Verify
|
||||
assert-true _is_wildcard_match array ./deeply/nested/build/.sh
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__no_dot_prefix() {
|
||||
# Setup
|
||||
local array=(sh)
|
||||
|
||||
# Verify
|
||||
assert-false _is_wildcard_match array ./build.sh
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__toplevel_file() {
|
||||
# Setup
|
||||
local array=(sh)
|
||||
|
||||
# Verify
|
||||
assert-true _is_wildcard_match array ./sh
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__multiple_extensions_first() {
|
||||
# Setup
|
||||
local array=(tmp log)
|
||||
|
||||
# Verify
|
||||
assert-true _is_wildcard_match array ./path/tmp
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__multiple_extensions_second() {
|
||||
# Setup
|
||||
local array=(tmp log)
|
||||
|
||||
# Verify
|
||||
assert-true _is_wildcard_match array ./path/log
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__dot_in_wildcard_first() {
|
||||
# Setup
|
||||
local array=(.tmp .log)
|
||||
|
||||
# Verify
|
||||
assert-true _is_wildcard_match array ./path/.tmp
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__dot_in_wildcard_second() {
|
||||
# Setup
|
||||
local array=(.tmp .log)
|
||||
|
||||
# Verify
|
||||
assert-true _is_wildcard_match array ./path/.log
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__dot_in_wildcard_no_dotfile() {
|
||||
# Setup
|
||||
local array=(.tmp .log)
|
||||
|
||||
# Verify
|
||||
assert-false _is_wildcard_match array ./path/xtmp
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__wildcard_match_dotfile() {
|
||||
# Setup
|
||||
local array=(\*.sh)
|
||||
|
||||
# Verify
|
||||
assert-true _is_wildcard_match array ./path/.sh
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__wildcard_match_file() {
|
||||
# Setup
|
||||
local array=(\*.sh)
|
||||
|
||||
# Verify
|
||||
assert-true _is_wildcard_match array ./path/subdir/build.sh
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__wildcard_no_matches_file() {
|
||||
# Setup
|
||||
local array=(\*.sh)
|
||||
|
||||
# Verify
|
||||
assert-false _is_wildcard_match array ./path/old
|
||||
}
|
||||
|
||||
function test__is_wildcard_match__wildcard_no_matches_path() {
|
||||
# Setup
|
||||
local array=(\*.sh)
|
||||
|
||||
# Verify
|
||||
assert-false _is_wildcard_match array ./path/build.sh/foo
|
||||
}
|
||||
|
||||
# shellcheck disable=2119
|
||||
run_tests
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Uncomment the next line to define a global platform for your project
|
||||
platform :osx, '10.13'
|
||||
platform :osx, '11.0'
|
||||
use_frameworks!
|
||||
|
||||
target 'Keyman' do
|
||||
|
|
@ -7,11 +7,11 @@ target 'Keyman' do
|
|||
# use_frameworks!
|
||||
|
||||
# Pods for Keyman
|
||||
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '8.38.0'
|
||||
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '8.57.3'
|
||||
|
||||
target 'KeymanTests' do
|
||||
inherit! :search_paths
|
||||
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '8.38.0'
|
||||
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '8.57.3'
|
||||
use_frameworks!
|
||||
# Pods for testing
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
PODS:
|
||||
- Sentry (8.38.0-beta.1):
|
||||
- Sentry/Core (= 8.38.0-beta.1)
|
||||
- Sentry/Core (8.38.0-beta.1)
|
||||
- Sentry (8.57.3):
|
||||
- Sentry/Core (= 8.57.3)
|
||||
- Sentry/Core (8.57.3)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Sentry (from `https://github.com/getsentry/sentry-cocoa.git`, tag `8.38.0`)
|
||||
- Sentry (from `https://github.com/getsentry/sentry-cocoa.git`, tag `8.57.3`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Sentry:
|
||||
:git: https://github.com/getsentry/sentry-cocoa.git
|
||||
:tag: 8.38.0
|
||||
:tag: 8.57.3
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
Sentry:
|
||||
:git: https://github.com/getsentry/sentry-cocoa.git
|
||||
:tag: 8.38.0
|
||||
:tag: 8.57.3
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Sentry: 4d6027fbfde9ddc35e5c368292843097d039db5f
|
||||
Sentry: c643eb180df401dd8c734c5036ddd9dd9218daa6
|
||||
|
||||
PODFILE CHECKSUM: 19b128c35d9c5e59f90d09522c053de65096696a
|
||||
PODFILE CHECKSUM: d45d4bde6c75c2c91314777c88c421e5e604d84d
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ fv,fv_ojibwa_rdot,ᐁᓂᔑᓇᐯᒧᐏᓐ (a-finals right w-dot),Eastern Subarc
|
|||
fv,fv_ojibwa_ifinal,ᐊᓂᔑᓇᐯᒧᐎᣙ (i-finals),Eastern Subarctic,fv_ojibwa_ifinal_kmw-9.0.js,1.0.3,oj,Ojibwa
|
||||
fv,fv_ojibwa_ifinal_rdot,ᐊᓂᔑᓇᐯᒧᐏᣙ (i-finals right w-dot),Eastern Subarctic,fv_ojibwa_ifinal_rdot_kmw-9.0.js,1.0.3,oj,Ojibwa
|
||||
fv,fv_naskapi,ᓇᔅᑲᐱ (Naskapi),Eastern Subarctic,fv_naskapi_kmw-9.0.js,9.3.1,nsk-Cans,Naskapi (Unified Canadian Aboriginal Syllabics)
|
||||
sil,sil_euro_latin,English,European,european2-1.6.js,3.0.3,en,English
|
||||
sil,sil_euro_latin,English,European,european2-1.6.js,3.0.4,en,English
|
||||
basic,basic_kbdcan,Français,European,canadian_french-1.0.js,1.1.1,fr-CA,French (Canada)
|
||||
fv,fv_anishinaabemowin,Anishinaabemowin,Great Lakes - St. Lawrence,fv_anishinaabemowin_kmw-9.0.js,10.2,oj,Ojibwa
|
||||
fv,fv_bodewadminwen,Bodéwadminwen-Nishnabémwen,Great Lakes - St. Lawrence,fv_bodewadminwen_kmw-9.0.js,9.1.1,pot-Latn,Potawatomi (Latin)
|
||||
|
|
@ -102,5 +102,6 @@ fv,fv_shihgotine_yati,Shıhgot'ı̨nę́ Yatı̨́,Western Subarctic,fv_shihgot
|
|||
fv,fv_southern_tutchone,Southern Tutchone,Western Subarctic,fv_southern_tutchone_kmw-9.0.js,9.3,tce-Latn,Southern Tutchone (Latin)
|
||||
fv,fv_tagizi_dene,Tāgizi Dene,Western Subarctic,fv_tagizi_dene_kmw-9.0.js,9.4,tgx-Latn,Tagish (Latin)
|
||||
fv,fv_tlicho_yatii,Tłı̨chǫ Yatıı̀,Western Subarctic,fv_tlicho_yatii_kmw-9.0.js,9.1.1,dgr-Latn,Dogrib (Latin)
|
||||
fv,fv_tlingityooxatangi,T’aku Tlingit Yóo X’átangí,Western Subarctic,fv_tlingityooxatangi-9.0.js,1.0,tli,T’aku Tlingit Yóo X’átangí
|
||||
fv,fv_dene_mb,ᑌᓀ ᔭᕠᐁ (Dene MB),Western Subarctic,fv_dene_mb_kmw-9.0.js,9.2.1,chp-Cans,Chipewyan (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_dene_nt,ᑌᓀ ᔭᕱᐁ (Dene NT),Western Subarctic,fv_dene_nt_kmw-9.0.js,9.2.1,chp-Cans,Chipewyan (Unified Canadian Aboriginal Syllabics)
|
||||
|
|
|
|||
|
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -243,7 +243,7 @@
|
|||
"dependencies": {
|
||||
"@keymanapp/common-types": "*",
|
||||
"eventemitter3": "^5.0.0",
|
||||
"fast-xml-parser": "^5.2.2",
|
||||
"fast-xml-parser": "^5.3.4",
|
||||
"path-browserify": "^1.0.1",
|
||||
"restructure": "^3.0.1",
|
||||
"sax": ">=0.6.0",
|
||||
|
|
@ -7841,9 +7841,9 @@
|
|||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.2.tgz",
|
||||
"integrity": "sha512-ZaCmslH75Jkfowo/x44Uq8KT5SutC5BFxHmY61nmTXPccw11PVuIXKUqC2hembMkJ3nPwTkQESXiUlsKutCbMg==",
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.4.tgz",
|
||||
"integrity": "sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
|
|
|
|||
|
|
@ -48,6 +48,6 @@ KEYMAN_DEFAULT_VERSION_UBUNTU_CONTAINER=noble # Ubuntu 24.04 Noble
|
|||
# Data versions -- see resources/standards-data/readme.md
|
||||
KEYMAN_VERSION_CLDR=46 # LDML Keyboards version
|
||||
KEYMAN_VERSION_ISO639_3=2024-05-22 # Date of last import
|
||||
KEYMAN_VERSION_LANGTAGS=2025-02-18 # _version value
|
||||
KEYMAN_VERSION_LANGTAGS=2026-02-03 # _version value
|
||||
KEYMAN_VERSION_LANGUAGE_SUBTAG_REGISTRY=2025-03-10 # Date from first line of language-subtag-registry
|
||||
KEYMAN_VERSION_UNICODE=17.0.0 # UCD + related data
|
||||
|
|
|
|||
|
|
@ -77,6 +77,31 @@ assert-succeeded() {
|
|||
fi
|
||||
}
|
||||
|
||||
_callfunc() {
|
||||
local command="$1"
|
||||
shift
|
||||
|
||||
"${command}" "$@"
|
||||
}
|
||||
|
||||
assert-true() {
|
||||
# shellcheck disable=SC2310
|
||||
if ! _callfunc "$@"; then
|
||||
messages+=("- Expected test to return true but it returned false
|
||||
")
|
||||
((test_failures++))
|
||||
fi
|
||||
}
|
||||
|
||||
assert-false() {
|
||||
# shellcheck disable=SC2310
|
||||
if _callfunc "$@"; then
|
||||
messages+=("- Expected test to return false but it returned true
|
||||
")
|
||||
((test_failures++))
|
||||
fi
|
||||
}
|
||||
|
||||
# setup() will run before each test
|
||||
# can be overriden in test script
|
||||
setup() {
|
||||
|
|
|
|||
|
|
@ -164,6 +164,74 @@ EOF
|
|||
assert-contains "${test_output_contents}" "PASS: test_succeeding1"
|
||||
}
|
||||
|
||||
# Helper functions for testing assert-true and assert-false
|
||||
function returns_true() {
|
||||
return 0
|
||||
}
|
||||
|
||||
function returns_false() {
|
||||
return 1
|
||||
}
|
||||
|
||||
## Tests for assert-true function
|
||||
|
||||
function test__assert_true__with_function_that_returns_true() {
|
||||
# Execute and Verify - should pass
|
||||
assert-true returns_true
|
||||
}
|
||||
|
||||
function test__assert_true__with_builtin_true() {
|
||||
# Execute and Verify - should pass
|
||||
assert-true true
|
||||
}
|
||||
|
||||
function test__assert_true__with_function_with_args_success() {
|
||||
# Execute and Verify - file exists
|
||||
assert-true test -f /etc/hostname
|
||||
}
|
||||
|
||||
function test__assert_true__increments_failure_on_false() {
|
||||
# Setup
|
||||
test_failures=0
|
||||
messages=()
|
||||
|
||||
# Execute function that returns false
|
||||
returns_false
|
||||
local result=$?
|
||||
|
||||
# Verify it failed
|
||||
assert-equal "${result}" "1"
|
||||
}
|
||||
|
||||
## Tests for assert-false function
|
||||
|
||||
function test__assert_false__with_function_that_returns_false() {
|
||||
# Execute and Verify - should pass
|
||||
assert-false returns_false
|
||||
}
|
||||
|
||||
function test__assert_false__with_builtin_false() {
|
||||
# Execute and Verify - should pass
|
||||
assert-false false
|
||||
}
|
||||
|
||||
function test__assert_false__with_function_with_args_success() {
|
||||
# Execute and Verify - file does not exist
|
||||
assert-false test -f /nonexistent/file/that/does/not/exist
|
||||
}
|
||||
|
||||
function test__assert_false__increments_failure_on_true() {
|
||||
# Setup
|
||||
test_failures=0
|
||||
messages=()
|
||||
|
||||
# Execute function that returns true
|
||||
returns_true
|
||||
local result=$?
|
||||
|
||||
# Verify it succeeded
|
||||
assert-equal "${result}" "0"
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2031
|
||||
if [[ "${1:-}" != "--recursive" ]]; then
|
||||
|
|
@ -14,7 +14,7 @@ _utils_inc_sh=1
|
|||
# 1: UPLOAD_DIR Directory where artifact can be found
|
||||
# 2: ARTIFACT_FILENAME Filename (without path) of artifact
|
||||
# 3: ARTIFACT_NAME Descriptive name of artifact
|
||||
# 4: ARTIFACT_TYPE File extension of artifact, without initial period (e.g. tar.gz)
|
||||
# 4: ARTIFACT_TYPE File extension of artifact, without initial period (e.g. tar.xz)
|
||||
# 5: PLATFORM Target platform for artifact
|
||||
#
|
||||
# TODO: Move to CI include?
|
||||
|
|
|
|||
|
|
@ -135,6 +135,10 @@ wrap-signcode() {
|
|||
}
|
||||
|
||||
wrap-symstore() {
|
||||
local target="$1"
|
||||
local slasht="$2"
|
||||
local product="$3"
|
||||
|
||||
if builder_is_ci_build && builder_is_ci_build_level_build; then
|
||||
builder_echo "Skipping symstore - buildLevel=build"
|
||||
return 0
|
||||
|
|
@ -147,10 +151,10 @@ wrap-symstore() {
|
|||
|
||||
"$ProgramFilesx86/Windows Kits/10/Debuggers/x64/symstore.exe" \
|
||||
add \
|
||||
//s "$KEYMAN_SYMSTOREPATH" \
|
||||
//s "$(cygpath -w "$KEYMAN_SYMSTOREPATH")" \
|
||||
//v "$KEYMAN_VERSION_WIN" \
|
||||
//c "Version: $KEYMAN_VERSION_WITH_TAG" \
|
||||
//compress //f "$@"
|
||||
//compress //f "$(cygpath -w "$target")" "$slasht" "$product"
|
||||
}
|
||||
|
||||
wrap-mt() {
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@
|
|||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="layout" minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:attribute name="@_first" />
|
||||
<xs:attribute name="@_last" />
|
||||
<xs:attribute name="@_mapSet" />
|
||||
<xs:attribute name="@_modifiers" />
|
||||
<xs:attribute name="@__first" />
|
||||
<xs:attribute name="@__last" />
|
||||
<xs:attribute name="@__mapSet" />
|
||||
<xs:attribute name="@__modifiers" />
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute />
|
||||
|
|
@ -29,15 +29,15 @@
|
|||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="modifier" minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:attribute name="@_keys" />
|
||||
<xs:attribute name="@__keys" />
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="@_mapIndex" />
|
||||
<xs:attribute name="@__mapIndex" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="@_defaultIndex" />
|
||||
<xs:attribute name="@_id" />
|
||||
<xs:attribute name="@__defaultIndex" />
|
||||
<xs:attribute name="@__id" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
|
|
@ -48,17 +48,17 @@
|
|||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="key" minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:attribute name="@_code" />
|
||||
<xs:attribute name="@_action" />
|
||||
<xs:attribute name="@_output" />
|
||||
<xs:attribute name="@__code" />
|
||||
<xs:attribute name="@__action" />
|
||||
<xs:attribute name="@__output" />
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="@_index" />
|
||||
<xs:attribute name="@_baseIndex" />
|
||||
<xs:attribute name="@_baseMapSet" />
|
||||
<xs:attribute name="@__index" />
|
||||
<xs:attribute name="@__baseIndex" />
|
||||
<xs:attribute name="@__baseMapSet" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attribute name="@_id" />
|
||||
<xs:attribute name="@__id" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
|
@ -70,12 +70,12 @@
|
|||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="when" minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:attribute name="@_state" />
|
||||
<xs:attribute name="@_output" />
|
||||
<xs:attribute name="@_next" />
|
||||
<xs:attribute name="@__state" />
|
||||
<xs:attribute name="@__output" />
|
||||
<xs:attribute name="@__next" />
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="@_id" />
|
||||
<xs:attribute name="@__id" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
|
|
@ -87,18 +87,18 @@
|
|||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="when" minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:attribute name="@_state" />
|
||||
<xs:attribute name="@_output" />
|
||||
<xs:attribute name="@__state" />
|
||||
<xs:attribute name="@__output" />
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:attribute name="@_group" />
|
||||
<xs:attribute name="@_id" />
|
||||
<xs:attribute name="@_name" />
|
||||
<xs:attribute name="@_maxout" />
|
||||
<xs:attribute name="@__group" />
|
||||
<xs:attribute name="@__id" />
|
||||
<xs:attribute name="@__name" />
|
||||
<xs:attribute name="@__maxout" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@
|
|||
"keyboard": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_group": {
|
||||
"@__group": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_id": {
|
||||
"@__id": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_maxout": {
|
||||
"@__maxout": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_name": {
|
||||
"@__name": {
|
||||
"type": "string"
|
||||
},
|
||||
"actions": {
|
||||
|
|
@ -24,20 +24,20 @@
|
|||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_id": {
|
||||
"@__id": {
|
||||
"type": "string"
|
||||
},
|
||||
"when": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_next": {
|
||||
"@__next": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_output": {
|
||||
"@__output": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_state": {
|
||||
"@__state": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
|
|
@ -65,33 +65,33 @@
|
|||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_id": {
|
||||
"@__id": {
|
||||
"type": "string"
|
||||
},
|
||||
"keyMap": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_baseIndex": {
|
||||
"@__baseIndex": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_baseMapSet": {
|
||||
"@__baseMapSet": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_index": {
|
||||
"@__index": {
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_action": {
|
||||
"@__action": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_code": {
|
||||
"@__code": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_output": {
|
||||
"@__output": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
|
|
@ -125,16 +125,16 @@
|
|||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_first": {
|
||||
"@__first": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_last": {
|
||||
"@__last": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_mapSet": {
|
||||
"@__mapSet": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_modifiers": {
|
||||
"@__modifiers": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
|
|
@ -152,24 +152,24 @@
|
|||
"modifierMap": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_defaultIndex": {
|
||||
"@__defaultIndex": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_id": {
|
||||
"@__id": {
|
||||
"type": "string"
|
||||
},
|
||||
"keyMapSelect": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_mapIndex": {
|
||||
"@__mapIndex": {
|
||||
"type": "string"
|
||||
},
|
||||
"modifier": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_keys": {
|
||||
"@__keys": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
|
|
@ -200,10 +200,10 @@
|
|||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"@_output": {
|
||||
"@__output": {
|
||||
"type": "string"
|
||||
},
|
||||
"@_state": {
|
||||
"@__state": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -60,10 +60,10 @@ function _make_release_source_tarball() {
|
|||
./scripts/reconf.sh
|
||||
PKG_CONFIG_PATH="${KEYMAN_ROOT}/core/build/arch/release/meson-private" ./scripts/dist.sh
|
||||
mkdir -p "upload/${KEYMAN_VERSION}"
|
||||
cp -a dist/*.tar.gz "upload/${KEYMAN_VERSION}"
|
||||
cp -a dist/*.tar.xz "upload/${KEYMAN_VERSION}"
|
||||
(
|
||||
cd "upload/${KEYMAN_VERSION}"
|
||||
sha256sum ./*.tar.gz > SHA256SUMS
|
||||
sha256sum ./*.tar.xz > SHA256SUMS
|
||||
builder_echo end "make source tarball" success "Make source tarball"
|
||||
)
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ function _sign_source_tarball() {
|
|||
|
||||
eval "$(gpg-agent -vv --daemon --allow-preset-passphrase --debug-level 9)"
|
||||
/usr/lib/gnupg/gpg-preset-passphrase --passphrase "${GPGKEYPW}" --preset "${GPGKEYGRIP}"
|
||||
for f in ./*.tar.gz; do gpg --output "${f}.asc" -a --detach-sig "${f}"; done
|
||||
for f in ./*.tar.xz; do gpg --output "${f}.asc" -a --detach-sig "${f}"; done
|
||||
/usr/lib/gnupg/gpg-preset-passphrase --forget "${GPGKEYGRIP}" || true
|
||||
builder_echo end "sign source tarball" success "Sign source tarball"
|
||||
)
|
||||
|
|
@ -84,10 +84,10 @@ function _sign_source_tarball() {
|
|||
function _publish_to_downloads() {
|
||||
builder_echo start "publish to downloads" "Publish to downloads.keyman.com"
|
||||
|
||||
local UPLOAD_DIR KEYMAN_TGZ
|
||||
local UPLOAD_DIR KEYMAN_TXZ
|
||||
|
||||
UPLOAD_DIR="upload/${KEYMAN_VERSION}"
|
||||
KEYMAN_TGZ="keyman-${KEYMAN_VERSION}.tar.gz"
|
||||
KEYMAN_TXZ="keyman-${KEYMAN_VERSION}.tar.xz"
|
||||
|
||||
# Set permissions as required on download site
|
||||
builder_echo "Setting upload file permissions for downloads.keyman.com"
|
||||
|
|
@ -96,7 +96,7 @@ function _publish_to_downloads() {
|
|||
chmod g+w "${UPLOAD_DIR}"/*
|
||||
chmod a+r "${UPLOAD_DIR}"/*
|
||||
|
||||
write_download_info "${UPLOAD_DIR}" "${KEYMAN_TGZ}" "Keyman for Linux" tar.gz linux
|
||||
write_download_info "${UPLOAD_DIR}" "${KEYMAN_TXZ}" "Keyman for Linux" tar.xz linux
|
||||
tc_rsync_upload "${UPLOAD_DIR}" "linux/${KEYMAN_TIER}"
|
||||
|
||||
builder_echo end "publish to downloads" success "Publish to downloads.keyman.com"
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@
|
|||
},
|
||||
"imports": {
|
||||
"#gesture-tools": "./src/engine/osk/gesture-processor/build/tools/obj/index.js",
|
||||
"#recorder": "./build/tools/testing/recorder/obj/index.js"
|
||||
"#recorder": "./build/tools/testing/recorder/obj/index.js",
|
||||
"#test-resources/*.js": "./build/test/resources/*.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
import { assert } from 'chai'
|
||||
import sinon from 'sinon';
|
||||
|
||||
import * as PromiseStatusModule from 'promise-status-async';
|
||||
const PromiseStatuses = PromiseStatusModule.PromiseStatuses;
|
||||
import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
|
||||
|
||||
import { InputSample, gestures, GestureDebugPath } from '@keymanapp/gesture-recognizer';
|
||||
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
import { TouchpathTurtle } from '#gesture-tools';
|
||||
|
||||
import { simulateMultiSourceMatcherInput } from "../../../../../resources/simulateMultiSourceInput.js";
|
||||
import { simulateMultiSourceMatcherInput } from "#test-resources/simulateMultiSourceInput.js";
|
||||
|
||||
import {
|
||||
FlickEndModel,
|
||||
|
|
@ -27,6 +24,8 @@ import {
|
|||
MainLongpressSourceModel
|
||||
} from './isolatedPathSpecs.js';
|
||||
|
||||
const PromiseStatuses = PromiseStatusModule.PromiseStatuses;
|
||||
|
||||
type PathInheritanceType = gestures.specs.ContactModel<string>['pathInheritance'];
|
||||
function dummyInheritanceMatcher(inheritanceType: PathInheritanceType): gestures.specs.GestureModel<string> {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
import { assert } from 'chai'
|
||||
import sinon from 'sinon';
|
||||
|
||||
import * as PromiseStatusModule from 'promise-status-async';
|
||||
import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
|
||||
|
||||
import { GestureModelDefs, buildGestureMatchInspector, gestures } from '@keymanapp/gesture-recognizer';
|
||||
import { ManagedPromise, timedPromise } from '@keymanapp/web-utils';
|
||||
|
||||
import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools';
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
import { assertGestureSequence, SequenceAssertion } from "#test-resources/sequenceAssertions.js";
|
||||
|
||||
const { matchers } = gestures;
|
||||
|
||||
// Huh... gotta do BOTH here? One for constructor use, the other for generic-parameter use?
|
||||
|
|
@ -16,10 +20,7 @@ type MatcherSelection<Type> = gestures.matchers.MatcherSelection<Type>;
|
|||
const getGestureModelSet = gestures.specs.getGestureModelSet;
|
||||
const modelSetForAction = gestures.matchers.modelSetForAction;
|
||||
|
||||
import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools';
|
||||
import { ManagedPromise, timedPromise } from '@keymanapp/web-utils';
|
||||
|
||||
import { assertGestureSequence, SequenceAssertion } from "../../../../../resources/sequenceAssertions.js";
|
||||
|
||||
import {
|
||||
LongpressModel,
|
||||
|
|
|
|||
|
|
@ -2,18 +2,13 @@ import { assert } from 'chai'
|
|||
import sinon from 'sinon';
|
||||
|
||||
import * as PromiseStatusModule from 'promise-status-async';
|
||||
const PromiseStatuses = PromiseStatusModule.PromiseStatuses;
|
||||
import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
|
||||
|
||||
import { simulateMultiSourceMatcherInput, simulateSelectorInput } from "../../../../../resources/simulateMultiSourceInput.js";
|
||||
|
||||
import { timedPromise } from '@keymanapp/web-utils';
|
||||
import { gestures } from '@keymanapp/gesture-recognizer';
|
||||
|
||||
import { TouchpathTurtle } from '#gesture-tools';
|
||||
|
||||
type MatcherSelection<Type> = gestures.matchers.MatcherSelection<Type>;
|
||||
type GestureModel<Type> = gestures.specs.GestureModel<Type>;
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
import { simulateMultiSourceMatcherInput, simulateSelectorInput } from "#test-resources/simulateMultiSourceInput.js";
|
||||
|
||||
import {
|
||||
LongpressModel,
|
||||
|
|
@ -26,6 +21,10 @@ import {
|
|||
LongpressDistanceThreshold
|
||||
} from './isolatedPathSpecs.js';
|
||||
|
||||
const PromiseStatuses = PromiseStatusModule.PromiseStatuses;
|
||||
type MatcherSelection<Type> = gestures.matchers.MatcherSelection<Type>;
|
||||
type GestureModel<Type> = gestures.specs.GestureModel<Type>;
|
||||
|
||||
describe("MatcherSelector", function () {
|
||||
beforeEach(function() {
|
||||
this.fakeClock = sinon.useFakeTimers();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import { assert } from 'chai'
|
||||
import sinon from 'sinon';
|
||||
|
||||
import * as PromiseStatusModule from 'promise-status-async';
|
||||
const PromiseStatuses = PromiseStatusModule.PromiseStatuses;
|
||||
import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
|
||||
|
||||
import { InputSample, GestureSource, gestures, CumulativePathStats } from '@keymanapp/gesture-recognizer';
|
||||
import { timedPromise } from '@keymanapp/web-utils';
|
||||
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
|
||||
import {
|
||||
InstantRejectionModel,
|
||||
InstantResolutionModel,
|
||||
|
|
@ -22,6 +21,8 @@ import {
|
|||
FlickEndThreshold
|
||||
} from './isolatedPathSpecs.js';
|
||||
|
||||
const PromiseStatuses = PromiseStatusModule.PromiseStatuses;
|
||||
|
||||
async function simulateSequence(
|
||||
samples: InputSample<string>[],
|
||||
fakeClock: sinon.SinonFakeTimers,
|
||||
|
|
|
|||
|
|
@ -1,20 +1,14 @@
|
|||
import { assert } from 'chai'
|
||||
import sinon from 'sinon';
|
||||
|
||||
import * as PromiseStatusModule from 'promise-status-async';
|
||||
import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
|
||||
import { PROMISE_PENDING } from 'promise-status-async';
|
||||
|
||||
import { GestureModelDefs, GestureSource, gestures, TouchpointCoordinator } from '@keymanapp/gesture-recognizer';
|
||||
const { matchers } = gestures;
|
||||
|
||||
// Huh... gotta do BOTH here? One for constructor use, the other for generic-parameter use?
|
||||
const { GestureSequence } = matchers;
|
||||
type GestureSequence<Type> = gestures.matchers.GestureSequence<Type>;
|
||||
|
||||
import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools';
|
||||
import { ManagedPromise, timedPromise } from '@keymanapp/web-utils';
|
||||
|
||||
import { assertGestureSequence, SequenceAssertion } from "../../../../../resources/sequenceAssertions.js";
|
||||
import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools';
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
import { assertGestureSequence, SequenceAssertion } from "#test-resources/sequenceAssertions.js";
|
||||
|
||||
import {
|
||||
LongpressModel,
|
||||
|
|
@ -25,9 +19,13 @@ import {
|
|||
SubkeySelectModel
|
||||
} from './isolatedGestureSpecs.js';
|
||||
|
||||
const LongpressDurationThreshold = LongpressModel.contacts[0].model.timer.duration;
|
||||
const { matchers } = gestures;
|
||||
|
||||
import { PROMISE_PENDING } from 'promise-status-async';
|
||||
// Huh... gotta do BOTH here? One for constructor use, the other for generic-parameter use?
|
||||
const { GestureSequence } = matchers;
|
||||
type GestureSequence<Type> = gestures.matchers.GestureSequence<Type>;
|
||||
|
||||
const LongpressDurationThreshold = LongpressModel.contacts[0].model.timer.duration;
|
||||
|
||||
const TestGestureModelDefinitions: GestureModelDefs<string> = {
|
||||
gestures: [
|
||||
|
|
|
|||
|
|
@ -774,7 +774,8 @@ end;
|
|||
procedure UpdateAvailableState.HandleInstallNow;
|
||||
begin
|
||||
bucStateContext.SetApplyNow(True);
|
||||
ChangeState(DownloadingState);
|
||||
// A new kmshell process will be used to download
|
||||
StartDownloadProcess;
|
||||
end;
|
||||
|
||||
{ DownloadingState }
|
||||
|
|
|
|||
|
|
@ -839,7 +839,12 @@ begin
|
|||
FResult := TUtilExecute.Shell(0, ShellPath, '', '-an');
|
||||
if not FResult then
|
||||
TKeymanSentryClient.Client.MessageEvent(Sentry.Client.SENTRY_LEVEL_ERROR,
|
||||
'TrmfMain: Shell Execute Update_ApplyNow Failed');
|
||||
'TrmfMain: Shell Execute Update_ApplyNow Failed')
|
||||
else
|
||||
ModalResult := mrAbort;
|
||||
// If a splash screen is currently open when "Install Now" is executed,
|
||||
// setting mrAbort ensures the splash screen is closed on the
|
||||
// return of "Keyman Configuration".
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ uses
|
|||
Windows, Controls, SysUtils, Classes, ErrorControlledRegistry, Forms, MessageIdentifiers, MessageIdentifierConsts, keymanapi_TLB;
|
||||
|
||||
procedure Run;
|
||||
procedure Main(Owner: TComponent = nil);
|
||||
function Main(Owner: TComponent = nil): TModalResult;
|
||||
|
||||
|
||||
type
|
||||
|
|
@ -164,10 +164,11 @@ procedure ShowKeyboardWelcome(PackageName: WideString); forward; // I2569
|
|||
procedure PrintKeyboard(KeyboardName: WideString); forward; // I2329
|
||||
function ProcessBackgroundUpdate(FMode: TKMShellMode; FSilent: Boolean): Boolean; forward;
|
||||
|
||||
procedure Main(Owner: TComponent = nil);
|
||||
function Main(Owner: TComponent = nil): TModalResult;
|
||||
var
|
||||
frmMain: TfrmMain;
|
||||
begin
|
||||
Result := mrNone;
|
||||
if not Assigned(Owner) then
|
||||
begin
|
||||
UfrmWebContainer.CreateForm(TfrmMain, frmMain);
|
||||
|
|
@ -180,7 +181,7 @@ begin
|
|||
begin
|
||||
with TfrmMain.Create(Owner) do
|
||||
try
|
||||
ShowModal;
|
||||
Result := ShowModal;
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ type
|
|||
FShowConfigurationOnLoad: Boolean;
|
||||
procedure WMUser_FormShown(var Message: TMessage); message WM_USER_FormShown;
|
||||
procedure WMUser(var Message: TMessage); message WM_USER;
|
||||
procedure ShowConfiguration;
|
||||
protected
|
||||
procedure FireCommand(const command: WideString; params: TStringList);
|
||||
override;
|
||||
|
|
@ -112,6 +113,17 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmSplash.ShowConfiguration;
|
||||
var
|
||||
configFrmResult: Integer;
|
||||
begin
|
||||
configFrmResult := Main(Self);
|
||||
if configFrmResult = mrAbort then
|
||||
Command_Exit
|
||||
else
|
||||
Do_Content_Render;
|
||||
end;
|
||||
|
||||
procedure TfrmSplash.TntFormActivate(Sender: TObject);
|
||||
begin
|
||||
inherited;
|
||||
|
|
@ -152,15 +164,17 @@ begin
|
|||
|
||||
if FShowConfigurationOnLoad then
|
||||
begin
|
||||
Main(Self);
|
||||
Do_Content_Render;
|
||||
ShowConfiguration;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmSplash.FireCommand(const command: WideString; params: TStringList);
|
||||
begin
|
||||
if command = 'start' then Command_Start
|
||||
else if command = 'config' then begin Main(Self); Do_Content_Render; end // I4393 // I4396
|
||||
else if command = 'config' then
|
||||
begin
|
||||
ShowConfiguration;
|
||||
end // I4393 // I4396
|
||||
else if command = 'hidesplash' then FShouldDisplay := False
|
||||
else if command = 'showsplash' then FShouldDisplay := True
|
||||
else if command = 'exit' then Command_Exit
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue