mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-20 21:07:52 +00:00
Merge pull request #13657 from keymanapp/chore/merge-dev-refactors-into-web-core
chore: merge dev refactors into epic/web-core 🎼
This commit is contained in:
commit
5c5b44df02
54 changed files with 625 additions and 203 deletions
|
|
@ -1,5 +1,13 @@
|
|||
# Keyman Version History
|
||||
|
||||
## 19.0.20 alpha 2025-04-01
|
||||
|
||||
* fix(android): move responsibility for setting keyboard height preference into `applyKeyboardHeight()` (#13578)
|
||||
|
||||
## 19.0.19 alpha 2025-03-31
|
||||
|
||||
* chore: merge beta to master B18S4 (#13606)
|
||||
|
||||
## 19.0.18 alpha 2025-03-25
|
||||
|
||||
* chore(developer): improve ldml code coverage (#13516)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
19.0.19
|
||||
19.0.21
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
package com.tavultesoft.kmapro;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -34,7 +33,6 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
private static ImageView sampleKeyboard = null;
|
||||
|
||||
// Keeps track of the adjusted keyboard height for saving
|
||||
private static SharedPreferences.Editor editor = null;
|
||||
private static int currentHeight = 0;
|
||||
private static ViewGroup.LayoutParams layoutParams;
|
||||
|
||||
|
|
@ -65,9 +63,6 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
adjustKeyboardHeightActivityTitle.setTextColor(ContextCompat.getColor(this, R.color.ms_white));
|
||||
adjustKeyboardHeightActivityTitle.setText(titleStr);
|
||||
|
||||
SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
editor = prefs.edit();
|
||||
|
||||
sampleKeyboard = (ImageView) findViewById(R.id.sample_keyboard);
|
||||
layoutParams = sampleKeyboard.getLayoutParams();
|
||||
currentHeight = KMManager.getKeyboardHeight(context);
|
||||
|
|
@ -77,9 +72,7 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
resetButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
// Clear the keyboard height preferences to reset
|
||||
editor.remove(KMManager.KMKey_KeyboardHeightPortrait);
|
||||
editor.remove(KMManager.KMKey_KeyboardHeightLandscape);
|
||||
editor.commit();
|
||||
KMManager.applyKeyboardHeight(context, KMManager.KeyboardHeight_Reset);
|
||||
|
||||
// Restore default height
|
||||
currentHeight = KMManager.getKeyboardHeight(context);
|
||||
|
|
@ -107,11 +100,7 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
// Save the currentHeight when the user releases
|
||||
int orientation = KMManager.getOrientation(context);
|
||||
String keyboardHeightKey = (orientation == Configuration.ORIENTATION_LANDSCAPE) ?
|
||||
KMManager.KMKey_KeyboardHeightLandscape : KMManager.KMKey_KeyboardHeightPortrait;
|
||||
editor.putInt(keyboardHeightKey, currentHeight);
|
||||
editor.commit();
|
||||
KMManager.applyKeyboardHeight(context, currentHeight);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -139,12 +128,5 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
refreshSampleKeyboard(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Apply the adjusted height on exit
|
||||
KMManager.applyKeyboardHeight(this, currentHeight);
|
||||
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import android.content.SharedPreferences;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Typeface;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
|
|
@ -273,6 +274,8 @@ public final class KMManager {
|
|||
// will be blocked.
|
||||
private static boolean maySendCrashReport = true;
|
||||
|
||||
private final static String KMEngine_PrefsKey = "KMAPreferences";
|
||||
|
||||
// Keyman public keys
|
||||
public static final String KMKey_ID = "id";
|
||||
public static final String KMKey_Name = "name";
|
||||
|
|
@ -295,8 +298,8 @@ public final class KMManager {
|
|||
public static final String KMKey_KMPInstall_Mode = "kmpInstallMode";
|
||||
public static final String KMKey_KeyboardModified = "lastModified";
|
||||
public static final String KMKey_KeyboardRTL = "rtl";
|
||||
public static final String KMKey_KeyboardHeightPortrait = "keyboardHeightPortrait";
|
||||
public static final String KMKey_KeyboardHeightLandscape = "keyboardHeightLandscape";
|
||||
private static final String KMKey_KeyboardHeightPortrait = "keyboardHeightPortrait";
|
||||
private static final String KMKey_KeyboardHeightLandscape = "keyboardHeightLandscape";
|
||||
|
||||
public static final String KMKey_LongpressDelay = "longpressDelay";
|
||||
|
||||
|
|
@ -345,6 +348,14 @@ public final class KMManager {
|
|||
public static final int KMMinimum_LongpressDelay = 300;
|
||||
public static final int KMMaximum_LongpressDelay = 1500;
|
||||
|
||||
// Default keyboard heights
|
||||
public static final int KeyboardHeight_Reset = 0; // To reset to default, applyKeyboardHeight
|
||||
public static final int KeyboardHeight_Invalid = -1; // If invalid orientation passed to functions
|
||||
public static int KeyboardHeight_Context_Portrait_Default = 0; // Default portrait height
|
||||
public static int KeyboardHeight_Context_Landscape_Default = 0; // Default landscape height
|
||||
public static int KeyboardHeight_Context_Portrait_Current = 0; // Current portrait height
|
||||
public static int KeyboardHeight_Context_Landscape_Current = 0; // Current landscape height
|
||||
|
||||
// Default prediction/correction setting
|
||||
public static final int KMDefault_Suggestion = SuggestionType.PREDICTIONS_WITH_CORRECTIONS.toInt();
|
||||
|
||||
|
|
@ -498,6 +509,12 @@ public final class KMManager {
|
|||
migrateCloudKeyboards(appContext);
|
||||
|
||||
CloudDownloadMgr.getInstance().initialize(appContext);
|
||||
|
||||
calculateDefaultKeyboardHeights(context);
|
||||
SharedPreferences prefs = context.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
KeyboardHeight_Context_Portrait_Current = prefs.getInt(KMManager.KMKey_KeyboardHeightPortrait, KMManager.KeyboardHeight_Context_Portrait_Default);
|
||||
KeyboardHeight_Context_Landscape_Current = prefs.getInt(KMManager.KMKey_KeyboardHeightLandscape, KMManager.KeyboardHeight_Context_Landscape_Default);
|
||||
|
||||
}
|
||||
|
||||
public static void executeResourceUpdate(Context aContext)
|
||||
|
|
@ -1463,7 +1480,7 @@ public final class KMManager {
|
|||
* @param suggestType SuggestionType
|
||||
*/
|
||||
public static void setMaySuggest(String languageID, SuggestionType suggestType) {
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putInt(KMManager.getLanguageAutoCorrectionPreferenceKey(languageID), suggestType.toInt());
|
||||
editor.commit();
|
||||
|
|
@ -1582,7 +1599,7 @@ public final class KMManager {
|
|||
model = model.replaceAll("\"", "'");
|
||||
|
||||
// When entering password field, maySuggest should override to disabled
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
int suggestionPreference = prefs.getInt(getLanguageAutoCorrectionPreferenceKey(languageID), KMDefault_Suggestion);
|
||||
|
||||
RelativeLayout.LayoutParams params;
|
||||
|
|
@ -2213,7 +2230,7 @@ public final class KMManager {
|
|||
*/
|
||||
public static int getLongpressDelay() {
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(
|
||||
appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
|
||||
return prefs.getInt(KMKey_LongpressDelay, KMDefault_LongpressDelay);
|
||||
}
|
||||
|
|
@ -2230,7 +2247,7 @@ public final class KMManager {
|
|||
}
|
||||
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(
|
||||
appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putInt(KMKey_LongpressDelay, longpressDelay);
|
||||
editor.commit();
|
||||
|
|
@ -2266,21 +2283,80 @@ public final class KMManager {
|
|||
return bannerHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current keyboard height in dp for the current device orientation
|
||||
*/
|
||||
public static int getKeyboardHeight(Context context) {
|
||||
int defaultHeight = (int) context.getResources().getDimension(R.dimen.keyboard_height);
|
||||
SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
|
||||
int orientation = getOrientation(context);
|
||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
return prefs.getInt(KMManager.KMKey_KeyboardHeightPortrait, defaultHeight);
|
||||
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
return prefs.getInt(KMManager.KMKey_KeyboardHeightLandscape, defaultHeight);
|
||||
}
|
||||
|
||||
return defaultHeight;
|
||||
return getKeyboardHeight(context, orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current keyboard height in dp for the specified device
|
||||
* orientation
|
||||
*/
|
||||
public static int getKeyboardHeight(Context context, int orientation) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
return KMManager.KeyboardHeight_Context_Portrait_Current;
|
||||
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
return KMManager.KeyboardHeight_Context_Landscape_Current;
|
||||
} else {
|
||||
return KMManager.KeyboardHeight_Invalid; // Invalid orientation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the keyboard height for the current orientation and store it in SharedPreferences.
|
||||
* If height is KMManager.KeyboardHeight_Reset, remove the stored height for that
|
||||
* orientation, resetting to the default height for the device/orientation.
|
||||
* @param context Context
|
||||
* @param height int - keyboard height in dp
|
||||
*/
|
||||
public static void applyKeyboardHeight(Context context, int height) {
|
||||
int orientation = getOrientation(context);
|
||||
applyKeyboardHeight(context, height, orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the keyboard height for the specified orientation and store it in SharedPreferences.
|
||||
* If height is KMManager.KeyboardHeight_Reset, remove the stored height for that orientation.
|
||||
* @param context Context
|
||||
* @param height int - keyboard height in dp
|
||||
* @param orientation int - Configuration.ORIENTATION_PORTRAIT or Configuration.ORIENTATION_LANDSCAPE
|
||||
*/
|
||||
public static void applyKeyboardHeight(Context context, int height, int orientation) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
int defaultHeightForContext = getDefaultKeyboardHeight(orientation);
|
||||
if (orientation != Configuration.ORIENTATION_PORTRAIT && orientation != Configuration.ORIENTATION_LANDSCAPE) {
|
||||
return; // Invalid orientation, do nothing
|
||||
}
|
||||
if (height == KMManager.KeyboardHeight_Reset) {
|
||||
// Passing 0 will reset the stored height for this orientation.
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
editor.remove(KMManager.KMKey_KeyboardHeightLandscape);
|
||||
} else /* (orientation == Configuration.ORIENTATION_PORTRAIT) */{
|
||||
editor.remove(KMManager.KMKey_KeyboardHeightPortrait);
|
||||
}
|
||||
height = defaultHeightForContext;
|
||||
} else {
|
||||
// Applying gating to 50%-200% of default height (following Keyman)
|
||||
if (height < (defaultHeightForContext / 2)) {
|
||||
height = (int) (defaultHeightForContext / 2);
|
||||
} else if (height > (defaultHeightForContext * 2)) {
|
||||
height = (int) (defaultHeightForContext * 2);
|
||||
}
|
||||
|
||||
// Store the new height based on the current orientation
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
editor.putInt(KMManager.KMKey_KeyboardHeightLandscape, height);
|
||||
} else /* (orientation == Configuration.ORIENTATION_PORTRAIT) */ {
|
||||
editor.putInt(KMManager.KMKey_KeyboardHeightPortrait, height);
|
||||
}
|
||||
}
|
||||
editor.commit();
|
||||
// Confirm new LayoutParams for in-app or system keyboards
|
||||
if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_INAPP)) {
|
||||
InAppKeyboard.loadJavascript(KMString.format("setOskHeight('%s')", height));
|
||||
RelativeLayout.LayoutParams params = getKeyboardLayoutParams();
|
||||
|
|
@ -2293,6 +2369,53 @@ public final class KMManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default keyboard height in dp for the current device
|
||||
* and orientation
|
||||
*/
|
||||
public static int getDefaultKeyboardHeight(Context context) {
|
||||
int orientation = getOrientation(context);
|
||||
return getDefaultKeyboardHeight(orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current keyboard height in dp for the specified orientation
|
||||
* for the current device
|
||||
*/
|
||||
public static int getDefaultKeyboardHeight(int orientation) {
|
||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
return KMManager.KeyboardHeight_Context_Portrait_Default;
|
||||
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
return KMManager.KeyboardHeight_Context_Landscape_Default;
|
||||
} else {
|
||||
return KMManager.KeyboardHeight_Invalid; // Invalid orientation
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateDefaultKeyboardHeights(Context context) {
|
||||
if (isTestMode()) {
|
||||
// Keyboard height not needed for unit tests #13578
|
||||
KeyboardHeight_Context_Portrait_Default = 0;
|
||||
KeyboardHeight_Context_Landscape_Default = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Resources resources = context.getResources();
|
||||
Configuration originalConfig = resources.getConfiguration();
|
||||
|
||||
Configuration newConfig = new Configuration(originalConfig);
|
||||
newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
|
||||
Context newContext = context.createConfigurationContext(newConfig);
|
||||
Resources newResources = newContext.getResources();
|
||||
KeyboardHeight_Context_Portrait_Default = (int) newResources.getDimension(R.dimen.keyboard_height);
|
||||
|
||||
newConfig = new Configuration(originalConfig);
|
||||
newConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||
newContext = context.createConfigurationContext(newConfig);
|
||||
newResources = newContext.getResources();
|
||||
KeyboardHeight_Context_Landscape_Default = (int) newResources.getDimension(R.dimen.keyboard_height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the area the window would occupy.
|
||||
* API 30+
|
||||
|
|
@ -2322,7 +2445,7 @@ public final class KMManager {
|
|||
}
|
||||
|
||||
protected static void setPersistentShouldShowHelpBubble(boolean flag) {
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(KMManager.KMKey_ShouldShowHelpBubble, flag);
|
||||
editor.commit();
|
||||
|
|
|
|||
|
|
@ -5,12 +5,17 @@ title: KMManager.applyKeyboardHeight()
|
|||
## Summary
|
||||
The **applyKeyboardHeight()** method sets the height of the keyboard frame for
|
||||
the device's current [screen orientation](https://developer.android.com/training/multiscreen/screensizes#TaskUseOriQuali)
|
||||
(portrait vs landscape).
|
||||
(portrait vs landscape) or a specified orientation.
|
||||
|
||||
## Syntax
|
||||
```java
|
||||
KMManager.applyKeyboardHeight(Context context, int height)
|
||||
```
|
||||
or
|
||||
|
||||
```java
|
||||
KMManager.applyKeyboardHeight(Context context, int height, int orientation)
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
|
|
@ -18,7 +23,10 @@ KMManager.applyKeyboardHeight(Context context, int height)
|
|||
: The context
|
||||
|
||||
`height`
|
||||
: The height of the keyboard frame in *density-independent pixels (dp)*
|
||||
: The height of the keyboard frame in *density-independent pixels (dp)*. Pass `KMManager.KeyboardHeight_Reset` to reset the keyboard height (for current orientation) to device-specific defaults.
|
||||
|
||||
`orientation` _(Optional)_
|
||||
: Accepts a [screen orientation](https://developer.android.com/training/multiscreen/screensizes#TaskUseOriQuali) value. This is most useful if you want to change the size of the keyboard in the other (non-current) orientation. If `orientation` is not defined, keyboard height is set for the current device orientation.
|
||||
|
||||
## Description
|
||||
Use this method when you want to increase or decrease the keyboard height for
|
||||
|
|
@ -30,11 +38,11 @@ For reference, here's a table of the default Keyman keyboard heights for various
|
|||
Device Type and Screen Orientation | Default height (dp) |
|
||||
|-----------------------------------|---------------------|
|
||||
| Default handset in portrait | 205 |
|
||||
| Default handset in landscape | 150 |
|
||||
| Default handset in landscape | 100 |
|
||||
| 7" tablet in portrait | 305 |
|
||||
| 7" tablet in landscape | 200 |
|
||||
| 7" tablet in landscape | 140 |
|
||||
| 10" tablet in portrait | 405 |
|
||||
| 10" tablet in landscape | 300 |
|
||||
| 10" tablet in landscape | 200 |
|
||||
|
||||
**Note:** This new keyboard height would be applied for all platforms, so an
|
||||
adjusted keyboard height for a phone would appear too small for a tablet.
|
||||
|
|
@ -50,5 +58,23 @@ The following script illustrates the use of `applyKeyboardHeight()`:
|
|||
KMManager.applyKeyboardHeight(this, newKeyboardHeight);
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```java
|
||||
import android.content.res.Configuration;
|
||||
...
|
||||
// Increase the Keyman keyboard height for landscape mode to 250dp (default Keyman value for most phones is 100dp)
|
||||
int newKeyboardHeight = 250;
|
||||
KMManager.applyKeyboardHeight(this, newKeyboardHeight, Configuration.ORIENTATION_LANDSCAPE);
|
||||
```
|
||||
|
||||
|
||||
The following script illustrates the use of `applyKeyboardHeight()` to reset keyboard height to default:
|
||||
|
||||
```java
|
||||
// Reset keyboard to default height
|
||||
KMManager.applyKeyboardHeight(this, KMManager.KeyboardHeight_Reset);
|
||||
```
|
||||
|
||||
## See also
|
||||
* [getKeyboardHeight()](getKeyboardHeight)
|
||||
|
|
|
|||
55
android/docs/engine/KMManager/getDefaultKeyboardHeight.md
Normal file
55
android/docs/engine/KMManager/getDefaultKeyboardHeight.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
title: KMManager.getDefaultKeyboardHeight()
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The **`getDefaultKeyboardHeight()`** method returns the default height of the keyboard frame for the current or specefied orientation.
|
||||
|
||||
## Syntax
|
||||
|
||||
``` javascript
|
||||
KMManager.getDefaultKeyboardHeight(Context context)
|
||||
```
|
||||
or
|
||||
``` javascript
|
||||
KMManager.getDefaultKeyboardHeight(int orientation)
|
||||
```
|
||||
|
||||
### Parameters (Choose One)
|
||||
|
||||
`context` _(Alternate)_
|
||||
: The context.
|
||||
|
||||
`orientation` _(Alternate)_
|
||||
: Accepts a [screen orientation](https://developer.android.com/training/multiscreen/screensizes#TaskUseOriQuali) value. This is most useful if you want to get the size of the keyboard in the other (non-current) orientation. If `orientation` parameter is not passed in, keyboard height is returned for the current device orientation.
|
||||
|
||||
### Returns
|
||||
|
||||
Returns the default height of the keyboard frame in *density-independent pixels (dp)*.
|
||||
|
||||
## Description
|
||||
|
||||
Use this method to get the default height of the keyboard frame.
|
||||
|
||||
## Examples
|
||||
|
||||
### Example: Using `getDefaultKeyboardHeight()`
|
||||
|
||||
The following script illustrate the use of `getDefaultKeyboardHeight()`:
|
||||
|
||||
``` javascript
|
||||
int keyboardHeight = KMManager.getDefaultKeyboardHeight(this);
|
||||
```
|
||||
or
|
||||
```java
|
||||
import android.content.res.Configuration;
|
||||
...
|
||||
// Get the current Keyman keyboard height for landscape mode.
|
||||
|
||||
int keyboardHeightLandscape = KMManager.getDefaultKeyboardHeight( Configuration.ORIENTATION_LANDSCAPE);
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [applyKeyboardHeight()](applyKeyboardHeight)
|
||||
|
|
@ -12,12 +12,19 @@ frame.
|
|||
``` javascript
|
||||
KMManager.getKeyboardHeight(Context context)
|
||||
```
|
||||
or
|
||||
``` javascript
|
||||
KMManager.getKeyboardHeight(Context context, int orientation)
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
`context`
|
||||
: The context.
|
||||
|
||||
`orientation` _(Optional)_
|
||||
: Accepts a [screen orientation](https://developer.android.com/training/multiscreen/screensizes#TaskUseOriQuali) value. This is most useful if you want to get the size of the keyboard in the other (non-current) orientation. If `orientation` parameter is not passed in, keyboard height is returned for the current device orientation.
|
||||
|
||||
### Returns
|
||||
|
||||
Returns the height of the keyboard frame in *density-independent pixels
|
||||
|
|
@ -36,7 +43,15 @@ The following script illustrate the use of `getKeyboardHeight()`:
|
|||
``` javascript
|
||||
int keyboardHeight = KMManager.getKeyboardHeight(this);
|
||||
```
|
||||
or
|
||||
```java
|
||||
import android.content.res.Configuration;
|
||||
...
|
||||
// Get the current Keyman keyboard height for landscape mode.
|
||||
|
||||
int keyboardHeightLandscape = KMManager.getKeyboardHeight(this, Configuration.ORIENTATION_LANDSCAPE);
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [applyKeyboardHeight](applyKeyboardHeight)
|
||||
- [applyKeyboardHeight()](applyKeyboardHeight)
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ title: Adjust Keyboard Height - Keyman for Android Help
|
|||
|
||||
This menu is used to adjust the height of the on-screen keyboard (OSK), which does not include the suggestion banner.
|
||||
|
||||
Drag the blank OSK at the bottom of the screen to increase or decrease the keyboard height for the device's current orientation (portrait vs landscape). The adjusted keyboard heights are automatically saved when the blank OSK is released.
|
||||
Drag the blank OSK at the bottom of the screen to increase or decrease the keyboard height for the device's current orientation (portrait vs landscape). Turn the device 90 degrees to the alternate orientation and repeat the process. The adjusted keyboard heights are automatically saved when the blank OSK is released.
|
||||
|
||||

|
||||
|
||||
### Reset to Default Height
|
||||
Press the button to reset the OSK height to the default values.
|
||||
Press the button to reset the OSK height (for the current orientation) to the default device-specific height.
|
||||
|
||||

|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs';
|
||||
import * as rd from 'readline';
|
||||
import * as fs from 'node:fs';
|
||||
import * as rd from 'node:readline';
|
||||
|
||||
export default async function hextobin(inputFilename: string, outputFilename?: string, options?: {silent?: boolean}): Promise<Uint8Array> {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import convertSourceMap from 'convert-source-map'; // Transforms sourcemaps among various common formats.
|
||||
// Base64, stringified-JSON, end-of-file comment...
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
// TODO: support multiple infiles to generate from multiple headers
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { CompilerEvent, CompilerCallbacks, CompilerPathCallbacks, CompilerFileSystemCallbacks,
|
||||
CompilerError, CompilerNetAsyncCallbacks, DefaultCompilerFileSystemAsyncCallbacks,
|
||||
CompilerFileSystemAsyncCallbacks,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@keymanapp/common-types": "*",
|
||||
"@sentry/node": "^7.57.0",
|
||||
"eventemitter3": "^5.0.0",
|
||||
"fast-xml-parser": "^5.0.9",
|
||||
"path-browserify": "^1.0.1",
|
||||
|
|
|
|||
|
|
@ -233,9 +233,10 @@ export enum CompilerErrorNamespace {
|
|||
*/
|
||||
LdmlKeyboardCompiler = 0x0000,
|
||||
/**
|
||||
* common/web/types errors between 0x1000…0x1FFF
|
||||
* common/web/utils errors between 0x1000…0x1FFF
|
||||
* was previously called CommonTypes
|
||||
*/
|
||||
CommonTypes = 0x1000,
|
||||
DeveloperUtils = 0x1000,
|
||||
/**
|
||||
* kmc-kmn errors between 0x2000…0x2FFF; these map to
|
||||
* the base codes found in kmn_compiler_errors.h, exclusive severity flags
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageDef as def, CompilerMessageSpec as m } from './compiler-interfaces.js';
|
||||
import { constants } from '@keymanapp/ldml-keyboard-constants';
|
||||
|
||||
const CommonTypesErrMask = CompilerErrorNamespace.CommonTypes;
|
||||
// const SevInfo = CompilerErrorSeverity.Info | CommonTypesErrMask;
|
||||
// const SevHint = CompilerErrorSeverity.Hint | CommonTypesErrMask;
|
||||
// const SevWarn = CompilerErrorSeverity.Warn | CommonTypesErrMask;
|
||||
const SevError = CompilerErrorSeverity.Error | CommonTypesErrMask;
|
||||
// const SevFatal = CompilerErrorSeverity.Fatal | CommonTypesErrMask;
|
||||
const DeveloperUtilsErrMask = CompilerErrorNamespace.DeveloperUtils;
|
||||
// const SevInfo = CompilerErrorSeverity.Info | DeveloperUtilsErrMask;
|
||||
// const SevHint = CompilerErrorSeverity.Hint | DeveloperUtilsErrMask;
|
||||
// const SevWarn = CompilerErrorSeverity.Warn | DeveloperUtilsErrMask;
|
||||
const SevError = CompilerErrorSeverity.Error | DeveloperUtilsErrMask;
|
||||
// const SevFatal = CompilerErrorSeverity.Fatal | DeveloperUtilsErrMask;
|
||||
|
||||
export class CommonTypesMessages {
|
||||
export class DeveloperUtilsMessages {
|
||||
// structured Ajv validation error
|
||||
static ERROR_SchemaValidationError = SevError | 0x0001;
|
||||
static Error_SchemaValidationError = (o:{instancePath:string, keyword:string, message: string, params: string}) => m(this.ERROR_SchemaValidationError,
|
||||
|
|
@ -58,4 +58,22 @@ export class CommonTypesMessages {
|
|||
this.ERROR_InvalidPackageFile,
|
||||
`Package source file is invalid: ${(o.e ?? 'unknown error').toString()}`
|
||||
);
|
||||
|
||||
static ERROR_InvalidProjectFile = SevError | 0x000A;
|
||||
static Error_InvalidProjectFile = (o:{message:string}) => m(
|
||||
this.ERROR_InvalidProjectFile,
|
||||
`Project file is not valid: ${def(o.message)}`,
|
||||
);
|
||||
|
||||
static ERROR_UnsupportedProjectVersion = SevError | 0x0013;
|
||||
static Error_UnsupportedProjectVersion = (o:{version:string}) => m(
|
||||
this.ERROR_UnsupportedProjectVersion,
|
||||
`Project version ${def(o.version)} is not supported by this version of Keyman Developer.`,
|
||||
);
|
||||
|
||||
static ERROR_ProjectFileCouldNotBeRead = SevError | 0x0014;
|
||||
static Error_ProjectFileCouldNotBeRead = () => m(
|
||||
this.ERROR_ProjectFileCouldNotBeRead,
|
||||
`Project file could not be read`
|
||||
);
|
||||
};
|
||||
|
|
@ -3,8 +3,6 @@
|
|||
*/
|
||||
|
||||
export { validateMITLicense } from './utils/validate-mit-license.js';
|
||||
export { KeymanSentry, SentryNodeOptions } from './utils/KeymanSentry.js';
|
||||
export { getOption, loadOptions, clearOptions } from './utils/options.js';
|
||||
export { escapeMarkdownChar } from './utils/markdown.js';
|
||||
export { KeymanUrls } from './utils/keyman-urls.js';
|
||||
|
||||
|
|
@ -63,7 +61,7 @@ export { defaultCompilerOptions, CompilerBaseOptions, CompilerOptions, CompilerE
|
|||
|
||||
export { UrlSubpathCompilerCallback } from './utils/UrlSubpathCompilerCallback.js';
|
||||
|
||||
export { CommonTypesMessages } from './common-messages.js';
|
||||
export { DeveloperUtilsMessages } from './developer-utils-messages.js';
|
||||
export * as SourceFilenamePatterns from './source-filename-patterns.js';
|
||||
export { KeymanXMLType, KeymanXMLWriter, KeymanXMLReader } from './xml-utils.js';
|
||||
|
||||
|
|
@ -73,3 +71,5 @@ export * as CloudUrls from './cloud-urls.js';
|
|||
export { getFontFamily, getFontFamilySync } from './font-family.js';
|
||||
|
||||
export * as ValidIds from './valid-ids.js';
|
||||
|
||||
export * as ProjectLoader from './project-loader.js';
|
||||
34
developer/src/common/web/utils/src/project-loader.ts
Normal file
34
developer/src/common/web/utils/src/project-loader.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { KeymanDeveloperProject } from "./types/kpj/keyman-developer-project.js";
|
||||
import { KPJFileReader } from "./types/kpj/kpj-file-reader.js";
|
||||
import { CompilerAsyncCallbacks, CompilerCallbacks } from "./compiler-callbacks.js";
|
||||
import { DeveloperUtilsMessages } from "./developer-utils-messages.js";
|
||||
|
||||
// TODO-KMC-TEST: refactor asyncCallbacks, make it a first-class part of CompilerCallbacks
|
||||
export async function loadProjectFromFile(infile: string, callbacks: CompilerCallbacks, asyncCallbacks: CompilerAsyncCallbacks = null): Promise<KeymanDeveloperProject> {
|
||||
const kpjData = await (asyncCallbacks ?? callbacks).fsAsync.readFile(infile);
|
||||
if(!kpjData) {
|
||||
callbacks.reportMessage(DeveloperUtilsMessages.Error_ProjectFileCouldNotBeRead());
|
||||
return null;
|
||||
}
|
||||
const reader = new KPJFileReader(callbacks);
|
||||
let kpj = null;
|
||||
try {
|
||||
kpj = reader.read(kpjData);
|
||||
if(!kpj) {
|
||||
callbacks.reportMessage(DeveloperUtilsMessages.Error_ProjectFileCouldNotBeRead());
|
||||
return null;
|
||||
}
|
||||
|
||||
if(kpj.KeymanDeveloperProject?.Options?.Version && kpj.KeymanDeveloperProject.Options.Version != "1.0" && kpj.KeymanDeveloperProject.Options.Version != "2.0") {
|
||||
callbacks.reportMessage(DeveloperUtilsMessages.Error_UnsupportedProjectVersion({version: kpj.KeymanDeveloperProject.Options.Version}));
|
||||
return null;
|
||||
}
|
||||
reader.validate(kpj);
|
||||
} catch(e) {
|
||||
callbacks.reportMessage(DeveloperUtilsMessages.Error_InvalidProjectFile({message: (e??'').toString()}));
|
||||
return null;
|
||||
}
|
||||
const project = await reader.transform(infile, kpj);
|
||||
return project;
|
||||
}
|
||||
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
import { util } from '@keymanapp/common-types';
|
||||
import boxXmlArray = util.boxXmlArray;
|
||||
|
||||
import { CommonTypesMessages } from "../../common-messages.js";
|
||||
import { DeveloperUtilsMessages } from "../../developer-utils-messages.js";
|
||||
import { CompilerCallbacks } from "../../compiler-callbacks.js";
|
||||
import { KeymanXMLReader } from "../../xml-utils.js";
|
||||
import { KpsPackage } from "./kps-file.js";
|
||||
|
|
@ -29,7 +29,7 @@ export class KpsFileReader {
|
|||
a = new KeymanXMLReader('kps')
|
||||
.parse(data) as KpsPackage;
|
||||
} catch(e) {
|
||||
this.callbacks.reportMessage(CommonTypesMessages.Error_InvalidPackageFile({e}));
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_InvalidPackageFile({e}));
|
||||
}
|
||||
return a;
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* Reads a LDML XML keyboard file into JS object tree and resolves imports
|
||||
*/
|
||||
import { SchemaValidators, util } from '@keymanapp/common-types';
|
||||
import { CommonTypesMessages } from '../../common-messages.js';
|
||||
import { DeveloperUtilsMessages } from '../../developer-utils-messages.js';
|
||||
import { CompilerCallbacks } from "../../compiler-callbacks.js";
|
||||
import { LDMLKeyboardXMLSourceFile, LKImport, ImportStatus } from './ldml-keyboard-xml.js';
|
||||
import { constants } from '@keymanapp/ldml-keyboard-constants';
|
||||
|
|
@ -219,7 +219,7 @@ export class LDMLKeyboardXMLSourceFileReader {
|
|||
const { base, path } = asImport;
|
||||
// If base is not an empty string (or null/undefined), then it must be 'cldr'
|
||||
if (base && base !== constants.cldr_import_base) {
|
||||
this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidBase({base, path, subtag}));
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_ImportInvalidBase({base, path, subtag}));
|
||||
return false;
|
||||
}
|
||||
let importData: Uint8Array;
|
||||
|
|
@ -228,7 +228,7 @@ export class LDMLKeyboardXMLSourceFileReader {
|
|||
// CLDR import
|
||||
const paths = path.split('/');
|
||||
if (paths[0] == '' || paths[1] == '' || paths.length !== 2) {
|
||||
this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidPath({base, path, subtag}));
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_ImportInvalidPath({base, path, subtag}));
|
||||
return false;
|
||||
}
|
||||
if (constants.treatAsLatest(paths[0])) {
|
||||
|
|
@ -241,7 +241,7 @@ export class LDMLKeyboardXMLSourceFileReader {
|
|||
importData = this.readLocalImportFile(path);
|
||||
}
|
||||
if (!importData || !importData.length) {
|
||||
this.callbacks.reportMessage(CommonTypesMessages.Error_ImportReadFail({base, path, subtag}));
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_ImportReadFail({base, path, subtag}));
|
||||
return false;
|
||||
}
|
||||
const importXml: any = this.loadUnboxed(importData); // TODO-LDML: have to load as any because it is an arbitrary part
|
||||
|
|
@ -249,7 +249,7 @@ export class LDMLKeyboardXMLSourceFileReader {
|
|||
|
||||
// importXml will have one property: the root element.
|
||||
if (!importRootNode) {
|
||||
this.callbacks.reportMessage(CommonTypesMessages.Error_ImportWrongRoot({base, path, subtag}));
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_ImportWrongRoot({base, path, subtag}));
|
||||
return false;
|
||||
}
|
||||
// pull all children of importXml[subtag] into obj
|
||||
|
|
@ -259,7 +259,7 @@ export class LDMLKeyboardXMLSourceFileReader {
|
|||
if (!Array.isArray(subsubval)) {
|
||||
// This is somewhat of an internal error, indicating that a non-mergeable XML file was imported
|
||||
// Not exercisable with the standard LDML imports.
|
||||
this.callbacks.reportMessage(CommonTypesMessages.Error_ImportMergeFail({base, path, subtag, subsubtag}));
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_ImportMergeFail({base, path, subtag, subsubtag}));
|
||||
return false;
|
||||
}
|
||||
// Mark all children as an import
|
||||
|
|
@ -286,7 +286,7 @@ export class LDMLKeyboardXMLSourceFileReader {
|
|||
public validate(source: LDMLKeyboardXMLSourceFile | LDMLKeyboardTestDataXMLSourceFile): boolean {
|
||||
if(!SchemaValidators.default.ldmlKeyboard3(source)) {
|
||||
for (const err of (<any>SchemaValidators.default.ldmlKeyboard3).errors) {
|
||||
this.callbacks.reportMessage(CommonTypesMessages.Error_SchemaValidationError({
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_SchemaValidationError({
|
||||
instancePath: err.instancePath,
|
||||
keyword: err.keyword,
|
||||
message: err.message || 'Unknown AJV Error', // docs say 'message' is optional if 'messages:false' in options
|
||||
|
|
@ -318,7 +318,7 @@ export class LDMLKeyboardXMLSourceFileReader {
|
|||
try {
|
||||
source = this.loadUnboxed(file);
|
||||
} catch(e) {
|
||||
this.callbacks.reportMessage(CommonTypesMessages.Error_InvalidXml({e}));
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_InvalidXml({e}));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -359,7 +359,7 @@ export class LDMLKeyboardXMLSourceFileReader {
|
|||
} else if (r.length === 1) {
|
||||
return r[0];
|
||||
} else {
|
||||
this.callbacks.reportMessage(CommonTypesMessages.Error_TestDataUnexpectedArray({subtag}));
|
||||
this.callbacks.reportMessage(DeveloperUtilsMessages.Error_TestDataUnexpectedArray({subtag}));
|
||||
return null; // ERROR
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
/**
|
||||
* Helpers and utilities for the Mocha tests.
|
||||
*/
|
||||
import * as path from 'path';
|
||||
import * as fs from "fs";
|
||||
import { fileURLToPath } from 'url';
|
||||
import * as path from 'node:path';
|
||||
import * as fs from "node:fs";
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
/**
|
||||
* Builds a path to the fixture with the given path components.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { makePathToFixture } from '../helpers/index.js';
|
|||
|
||||
import { KpsFileReader } from "../../src/types/kps/kps-file-reader.js";
|
||||
import { KpsFileWriter } from '../../src/types/kps/kps-file-writer.js';
|
||||
import { CommonTypesMessages } from '../../src/common-messages.js';
|
||||
import { DeveloperUtilsMessages } from '../../src/developer-utils-messages.js';
|
||||
|
||||
const callbacks = new TestCompilerCallbacks();
|
||||
|
||||
|
|
@ -80,6 +80,6 @@ describe('kps-file-reader', function () {
|
|||
|
||||
assert.isNull(kps);
|
||||
assert.lengthOf(callbacks.messages, 1);
|
||||
assert.isTrue(callbacks.hasMessage(CommonTypesMessages.ERROR_InvalidPackageFile));
|
||||
assert.isTrue(callbacks.hasMessage(DeveloperUtilsMessages.ERROR_InvalidPackageFile));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'mocha';
|
||||
import {assert} from 'chai';
|
||||
import { DeveloperUtilsMessages } from '../../src/developer-utils-messages.js';
|
||||
import { Constants } from '@keymanapp/common-types';
|
||||
import { CommonTypesMessages } from '../../src/common-messages.js';
|
||||
import { LKKey, ImportStatus } from '../../src/types/ldml-keyboard/ldml-keyboard-xml.js';
|
||||
import { testReaderCases } from '../helpers/reader-callback-test.js';
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ describe('ldml keyboard xml reader tests', function () {
|
|||
testReaderCases([
|
||||
{
|
||||
subpath: 'invalid-structure-per-dtd.xml',
|
||||
errors: [CommonTypesMessages.Error_SchemaValidationError({
|
||||
errors: [DeveloperUtilsMessages.Error_SchemaValidationError({
|
||||
instancePath: '/keyboard3',
|
||||
keyword: 'required',
|
||||
message: `must have required property 'info'`,
|
||||
|
|
@ -28,7 +28,7 @@ describe('ldml keyboard xml reader tests', function () {
|
|||
},
|
||||
{
|
||||
subpath: 'invalid-conforms-to.xml',
|
||||
errors: [CommonTypesMessages.Error_SchemaValidationError({
|
||||
errors: [DeveloperUtilsMessages.Error_SchemaValidationError({
|
||||
instancePath: '/keyboard3/conformsTo',
|
||||
keyword: 'enum',
|
||||
message: `must be equal to one of the allowed values`,
|
||||
|
|
@ -150,7 +150,7 @@ describe('ldml keyboard xml reader tests', function () {
|
|||
subpath: 'invalid-import-base.xml',
|
||||
loadfail: true,
|
||||
errors: [
|
||||
CommonTypesMessages.Error_ImportInvalidBase({
|
||||
DeveloperUtilsMessages.Error_ImportInvalidBase({
|
||||
base: 'SOME_INVALID_BASE',
|
||||
path: 'B',
|
||||
subtag: 'C'
|
||||
|
|
@ -161,7 +161,7 @@ describe('ldml keyboard xml reader tests', function () {
|
|||
subpath: 'invalid-import-local.xml',
|
||||
loadfail: true,
|
||||
errors: [
|
||||
CommonTypesMessages.Error_ImportReadFail({
|
||||
DeveloperUtilsMessages.Error_ImportReadFail({
|
||||
base: undefined,
|
||||
path: 'keys-Zyyy-DOESNOTEXIST.xml',
|
||||
subtag: 'keys'
|
||||
|
|
@ -172,7 +172,7 @@ describe('ldml keyboard xml reader tests', function () {
|
|||
subpath: 'invalid-import-path.xml',
|
||||
loadfail: true,
|
||||
errors: [
|
||||
CommonTypesMessages.Error_ImportInvalidPath({
|
||||
DeveloperUtilsMessages.Error_ImportInvalidPath({
|
||||
base: 'cldr',
|
||||
path: '45/too/many/slashes/leading/to/nothing-Zxxx-does-not-exist.xml',
|
||||
subtag: null,
|
||||
|
|
@ -183,7 +183,7 @@ describe('ldml keyboard xml reader tests', function () {
|
|||
subpath: 'invalid-import-readfail.xml',
|
||||
loadfail: true,
|
||||
errors: [
|
||||
CommonTypesMessages.Error_ImportReadFail({
|
||||
DeveloperUtilsMessages.Error_ImportReadFail({
|
||||
base: 'cldr',
|
||||
path: '45/none-Zxxx-does-not-exist.xml',
|
||||
subtag: null,
|
||||
|
|
@ -194,7 +194,7 @@ describe('ldml keyboard xml reader tests', function () {
|
|||
subpath: 'invalid-import-wrongroot.xml',
|
||||
loadfail: true,
|
||||
errors: [
|
||||
CommonTypesMessages.Error_ImportWrongRoot({
|
||||
DeveloperUtilsMessages.Error_ImportWrongRoot({
|
||||
base: null,
|
||||
path: '45/keys-Zyyy-punctuation.xml',
|
||||
subtag: 'flicks',
|
||||
|
|
|
|||
|
|
@ -4,7 +4,23 @@
|
|||
* Copy a keyboard or lexical model project
|
||||
*/
|
||||
|
||||
import { CloudUrls, GitHubUrls, CompilerCallbacks, KeymanCompiler, KeymanCompilerArtifact, KeymanCompilerArtifacts, KeymanCompilerResult, KeymanDeveloperProject, KeymanDeveloperProjectOptions, KPJFileReader, KPJFileWriter, KpsFileReader, KpsFileWriter, ValidIds, CompilerBaseOptions } from "@keymanapp/developer-utils";
|
||||
import {
|
||||
CloudUrls,
|
||||
GitHubUrls,
|
||||
CompilerCallbacks,
|
||||
KeymanCompiler,
|
||||
KeymanCompilerArtifact,
|
||||
KeymanCompilerArtifacts,
|
||||
KeymanCompilerResult,
|
||||
KeymanDeveloperProject,
|
||||
KeymanDeveloperProjectOptions,
|
||||
ProjectLoader,
|
||||
KPJFileWriter,
|
||||
KpsFileReader,
|
||||
KpsFileWriter,
|
||||
ValidIds,
|
||||
CompilerBaseOptions,
|
||||
} from "@keymanapp/developer-utils";
|
||||
import { KeymanFileTypes } from "@keymanapp/common-types";
|
||||
|
||||
import { CopierMessages } from "./copier-messages.js";
|
||||
|
|
@ -124,7 +140,7 @@ export class KeymanProjectCopier implements KeymanCompiler {
|
|||
this.sourceId = this.callbacks.path.basename(projectSource, KeymanFileTypes.Source.Project);
|
||||
|
||||
// copy project file
|
||||
const project = await this.loadProjectFromFile(projectSource);
|
||||
const project = await ProjectLoader.loadProjectFromFile(projectSource, this.callbacks, this.asyncCallbacks);
|
||||
if(!project) {
|
||||
// loadProjectFromFile already reported errors
|
||||
return null;
|
||||
|
|
@ -637,31 +653,6 @@ export class KeymanProjectCopier implements KeymanCompiler {
|
|||
return this.callbacks.path.join(this.outPath, 'source');
|
||||
}
|
||||
|
||||
private async loadProjectFromFile(filename: string): Promise<KeymanDeveloperProject> {
|
||||
const kpjData = await this.asyncCallbacks.fsAsync.readFile(filename);
|
||||
const reader = new KPJFileReader(this.asyncCallbacks);
|
||||
let kpj = null;
|
||||
try {
|
||||
kpj = reader.read(kpjData);
|
||||
if(!kpj) {
|
||||
this.callbacks.reportMessage(CopierMessages.Error_ProjectFileCouldNotBeRead({filename}));
|
||||
return null;
|
||||
}
|
||||
|
||||
if(kpj.KeymanDeveloperProject?.Options?.Version && kpj.KeymanDeveloperProject.Options.Version != "1.0" && kpj.KeymanDeveloperProject.Options.Version != "2.0") {
|
||||
this.callbacks.reportMessage(CopierMessages.Error_UnsupportedProjectVersion({filename, version: kpj.KeymanDeveloperProject.Options.Version}));
|
||||
return null;
|
||||
}
|
||||
reader.validate(kpj);
|
||||
} catch(e) {
|
||||
this.callbacks.reportMessage(CopierMessages.Error_InvalidProjectFile({filename, message: (e ?? '').toString()}));
|
||||
return null;
|
||||
}
|
||||
const project = await reader.transform(filename, kpj);
|
||||
|
||||
return project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write artifacts from a successful compile to disk, via callbacks methods.
|
||||
* The artifacts written will include all files from the project, across
|
||||
|
|
|
|||
|
|
@ -92,22 +92,9 @@ export class CopierMessages {
|
|||
`The package source file '${def(o.filename)}' could not be loaded. The file may have an invalid format`
|
||||
);
|
||||
|
||||
static ERROR_UnsupportedProjectVersion = SevError | 0x000D;
|
||||
static Error_UnsupportedProjectVersion = (o:{filename: string, version: string}) => m(this.ERROR_UnsupportedProjectVersion,
|
||||
`Project version ${def(o.version)} for '${def(o.filename)}' is not supported by this version of Keyman Developer`
|
||||
);
|
||||
|
||||
static ERROR_InvalidProjectFile = SevError | 0x000E;
|
||||
static Error_InvalidProjectFile = (o:{filename: string, message: string}) => m(
|
||||
this.ERROR_InvalidProjectFile,
|
||||
`Project file '${def(o.filename)}' is not valid: ${def(o.message)}`
|
||||
);
|
||||
|
||||
static ERROR_ProjectFileCouldNotBeRead = SevError | 0x000F;
|
||||
static Error_ProjectFileCouldNotBeRead = (o:{filename: string}) => m(
|
||||
this.ERROR_ProjectFileCouldNotBeRead,
|
||||
`Project file '${def(o.filename)}' could not be read`
|
||||
);
|
||||
// 0x000D ERROR_UnsupportedProjectVersion: moved to developer-utils-messages
|
||||
// 0x000E ERROR_InvalidProjectFile: moved to developer-utils-messages
|
||||
// 0x000F ERROR_ProjectFileCouldNotBeRead: moved to developer-utils-messages
|
||||
|
||||
static INFO_DryRun = SevInfo | 0x0010;
|
||||
static Info_DryRun = (o:{outPath: string}) => m(
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"paths": {
|
||||
"@keymanapp/keyman-version": ["../../../common/web/keyman-version/keyman-version.mts"],
|
||||
"@keymanapp/common-types": ["../../../common/web/types/src/main"],
|
||||
"@keymanapp/developer-utils": ["../common/web/utils"],
|
||||
},
|
||||
|
||||
},
|
||||
|
|
@ -21,5 +22,6 @@
|
|||
"references": [
|
||||
{ "path": "../../../common/web/keyman-version" },
|
||||
{ "path": "../../../common/web/types/" },
|
||||
{ "path": "../common/web/utils/" },
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
* If you need to add more Unicode blocks, customize SPACELESS_SCRIPT_BLOCKS.
|
||||
*/
|
||||
|
||||
import {readFileSync} from "fs";
|
||||
import * as path from "path";
|
||||
import {readFileSync} from "node:fs";
|
||||
import * as path from "node:path";
|
||||
|
||||
// Where to find UnicodeData.txt and Blocks.txt
|
||||
const UCD_DIR = path.join("..", "..", "..", "..", "resources", "standards-data", "unicode-character-database");
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ export class PackageCompilerMessages {
|
|||
`The source file '${def(o.filename)}' should not be included in the package; instead include the compiled result.`
|
||||
);
|
||||
|
||||
// 0x001E was ERROR_InvalidPackageFile, now CommonTypesMessages.Error_InvalidPackageFile
|
||||
// 0x001E was ERROR_InvalidPackageFile, now DeveloperUtilsMessages.Error_InvalidPackageFile
|
||||
|
||||
static ERROR_FileRecordIsMissingName = SevError | 0x001F;
|
||||
static Error_FileRecordIsMissingName = (o:{description:string}) => m(this.ERROR_FileRecordIsMissingName,
|
||||
|
|
@ -191,7 +191,7 @@ export class PackageCompilerMessages {
|
|||
`The format for version numbers should be number[.number[.number]]. Each
|
||||
number component should be an integer, without leading zeroes.`
|
||||
);
|
||||
|
||||
|
||||
static ERROR_PackageMustNotContainItself = SevError | 0x0028;
|
||||
static Error_PackageMustNotContainItself = (o:{outputFilename: string}) => m(
|
||||
this.ERROR_PackageMustNotContainItself, `The package may not include a .kmp file of the same name '${def(o.outputFilename)}'.`, `
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { buildActivities, buildKeyboardInfoActivity, buildModelInfoActivity } fr
|
|||
import { InfrastructureMessages } from '../../messages/infrastructureMessages.js';
|
||||
import { loadProject } from '../../util/projectLoader.js';
|
||||
import { ExtendedCompilerOptions } from '../../util/extendedCompilerOptions.js';
|
||||
import { getOption } from '@keymanapp/developer-utils';
|
||||
import { getOption } from '../../util/options.js';
|
||||
|
||||
export class BuildProject extends BuildActivity {
|
||||
public get name(): string { return 'Project'; }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
import { Command, Option } from 'commander';
|
||||
import { declareBuild } from './commands/build.js';
|
||||
import { declareAnalyze } from './commands/analyze.js';
|
||||
import { KeymanSentry, loadOptions } from '@keymanapp/developer-utils';
|
||||
import { loadOptions } from './util/options.js';
|
||||
import { KeymanSentry } from './util/KeymanSentry.js';
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { TestKeymanSentry } from './util/TestKeymanSentry.js';
|
||||
import { exitProcess } from './util/sysexits.js';
|
||||
|
|
|
|||
|
|
@ -38,9 +38,7 @@ export class InfrastructureMessages {
|
|||
static Info_FileNotBuiltSuccessfully = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m(this.INFO_FileNotBuiltSuccessfully,
|
||||
`${def(o.relativeFilename)} failed to build.`)});
|
||||
|
||||
static ERROR_InvalidProjectFile = SevError | 0x0008;
|
||||
static Error_InvalidProjectFile = (o:{message:string}) => m(this.ERROR_InvalidProjectFile,
|
||||
`Project file is not valid: ${def(o.message)}`);
|
||||
// 0x0008: ERROR_InvalidProjectFile moved to DeveloperUtilsMessages
|
||||
|
||||
static HINT_FilenameHasDifferingCase = SevHint | 0x0009;
|
||||
static Hint_FilenameHasDifferingCase = (o:{reference:string, filename:string}) => m(this.HINT_FilenameHasDifferingCase,
|
||||
|
|
@ -84,9 +82,7 @@ export class InfrastructureMessages {
|
|||
static Error_InvalidProjectFolder = (o:{folderName:string}) => m(this.ERROR_InvalidProjectFolder,
|
||||
`The folder ${def(o.folderName)} does not appear to be a Keyman Developer project.`);
|
||||
|
||||
static ERROR_UnsupportedProjectVersion = SevError | 0x0013;
|
||||
static Error_UnsupportedProjectVersion = (o:{version:string}) => m(this.ERROR_UnsupportedProjectVersion,
|
||||
`Project version ${def(o.version)} is not supported by this version of Keyman Developer.`);
|
||||
// 0x0013: ERROR_UnsupportedProjectVersion moved to developer-utils-messages
|
||||
|
||||
static HINT_ProjectIsVersion10 = SevHint | 0x0014;
|
||||
static Hint_ProjectIsVersion10 = () => m(this.HINT_ProjectIsVersion10,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { CommonTypesMessages, CompilerErrorNamespace } from '@keymanapp/developer-utils';
|
||||
import { DeveloperUtilsMessages, CompilerErrorNamespace } from '@keymanapp/developer-utils';
|
||||
import { AnalyzerMessages } from '@keymanapp/kmc-analyze';
|
||||
import { CopierMessages } from '@keymanapp/kmc-copy';
|
||||
import { GeneratorMessages } from '@keymanapp/kmc-generate';
|
||||
|
|
@ -13,7 +13,7 @@ import { InfrastructureMessages } from './infrastructureMessages.js';
|
|||
// Maps every compiler error namespace to the corresponding implementation
|
||||
const messageNamespaces: Record<CompilerErrorNamespace, any> = {
|
||||
[CompilerErrorNamespace.LdmlKeyboardCompiler]: LdmlCompilerMessages,
|
||||
[CompilerErrorNamespace.CommonTypes]: CommonTypesMessages,
|
||||
[CompilerErrorNamespace.DeveloperUtils]: DeveloperUtilsMessages,
|
||||
[CompilerErrorNamespace.KmnCompiler]: KmnCompilerMessages,
|
||||
[CompilerErrorNamespace.ModelCompiler]: ModelCompilerMessages,
|
||||
[CompilerErrorNamespace.PackageCompiler]: PackageCompilerMessages,
|
||||
|
|
@ -38,7 +38,7 @@ export type CompilerMessageSource = {
|
|||
// TODO: consolidate with messageNamespaces above
|
||||
export const messageSources: Record<CompilerErrorNamespace, CompilerMessageSource> = {
|
||||
[CompilerErrorNamespace.LdmlKeyboardCompiler]: { module: 'kmc-ldml', class: LdmlCompilerMessages },
|
||||
[CompilerErrorNamespace.CommonTypes]: { module: 'common-types', class: CommonTypesMessages },
|
||||
[CompilerErrorNamespace.DeveloperUtils]: { module: 'developer-utils', class: DeveloperUtilsMessages },
|
||||
[CompilerErrorNamespace.KmnCompiler]: { module: 'kmc-kmn', class: KmnCompilerMessages },
|
||||
[CompilerErrorNamespace.ModelCompiler]: { module: 'kmc-model', class: ModelCompilerMessages },
|
||||
[CompilerErrorNamespace.PackageCompiler]: { module: 'kmc-package', class: PackageCompilerMessages },
|
||||
|
|
|
|||
104
developer/src/kmc/src/util/KeymanSentry.ts
Normal file
104
developer/src/kmc/src/util/KeymanSentry.ts
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// TODO: this is duplicated in server.js
|
||||
import Sentry from "@sentry/node";
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { getOption } from "./options.js";
|
||||
|
||||
export type SentryNodeOptions = Sentry.NodeOptions;
|
||||
|
||||
/**
|
||||
* Maximum delay on shutdown of process to send pending events
|
||||
* to Sentry, in msec
|
||||
*/
|
||||
const CLOSE_TIMEOUT = 2000;
|
||||
|
||||
let isInit = false;
|
||||
|
||||
export class KeymanSentry {
|
||||
|
||||
static isEnabled() {
|
||||
if(process.argv.includes('--no-error-reporting')) {
|
||||
return false;
|
||||
}
|
||||
if(process.argv.includes('--error-reporting')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return getOption('automatically report errors', true);
|
||||
}
|
||||
|
||||
static init(options?: SentryNodeOptions) {
|
||||
options = options ?? {};
|
||||
Sentry.init({
|
||||
...options,
|
||||
dsn: 'https://39b25a09410349a58fe12aaf721565af@o1005580.ingest.sentry.io/5983519', // Keyman Developer
|
||||
environment: KEYMAN_VERSION.VERSION_ENVIRONMENT,
|
||||
release: KEYMAN_VERSION.VERSION_GIT_TAG,
|
||||
});
|
||||
isInit = true;
|
||||
}
|
||||
|
||||
private static writeSentryMessage(eventId: string) {
|
||||
process.stderr.write(`
|
||||
This error has been automatically reported to the Keyman team.
|
||||
Identifier: ${eventId}
|
||||
Application: Keyman Developer
|
||||
Reported at: https://sentry.io/organizations/keyman/projects/keyman-developer/events/${eventId}/
|
||||
`);
|
||||
}
|
||||
|
||||
static async reportException(e: any, silent: boolean = true) {
|
||||
if(isInit) {
|
||||
const eventId = await Sentry.captureException(e);
|
||||
if(!silent) {
|
||||
this.writeSentryMessage(eventId);
|
||||
}
|
||||
return eventId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static captureMessage(message: string) {
|
||||
if(isInit) {
|
||||
return Sentry.captureMessage(message);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* capture an exception for Sentry; note that in local environments, this will normally
|
||||
* throw the exception rather than sending to Sentry
|
||||
* @param e
|
||||
* @param force if true, reports to Sentry even in local environments
|
||||
*/
|
||||
static async captureException(e: any, force?: boolean): Promise<never> {
|
||||
if(isInit) {
|
||||
// For local development, we don't want to bury the trace; we need the cast to avoid
|
||||
// TS2367 (comparison appears to be unintentional)
|
||||
if(!force && (KEYMAN_VERSION.VERSION_ENVIRONMENT as string) == 'local') {
|
||||
throw e;
|
||||
}
|
||||
|
||||
const eventId = Sentry.captureException(e);
|
||||
process.stderr.write(`
|
||||
Fatal error: ${(e??'').toString()}
|
||||
`);
|
||||
this.writeSentryMessage(eventId);
|
||||
await this.close();
|
||||
|
||||
process.exit(1);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
static async close() {
|
||||
if(isInit) {
|
||||
try {
|
||||
await Sentry.close(CLOSE_TIMEOUT);
|
||||
} catch(e) {
|
||||
// ignore any errors here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import { CompilerCallbacks, CompilerEvent,
|
|||
import { InfrastructureMessages } from '../messages/infrastructureMessages.js';
|
||||
import chalk from 'chalk';
|
||||
import supportsColor from 'supports-color';
|
||||
import { KeymanSentry } from '@keymanapp/developer-utils';
|
||||
import { KeymanSentry } from './KeymanSentry.js';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const color = chalk.default;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { KmnCompiler } from "@keymanapp/kmc-kmn";
|
||||
import { NodeCompilerCallbacks } from "./NodeCompilerCallbacks.js";
|
||||
import { KeymanSentry, SentryNodeOptions } from '@keymanapp/developer-utils';
|
||||
import { KeymanSentry, SentryNodeOptions } from './KeymanSentry.js';
|
||||
|
||||
const cli = process.argv.join(' ');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Sentry from "@sentry/node";
|
||||
import * as process from "node:process";
|
||||
import { SentryNodeOptions } from "@keymanapp/developer-utils";
|
||||
import { SentryNodeOptions } from "./KeymanSentry.js";
|
||||
|
||||
Sentry.setContext('Command Line', {
|
||||
// obfusate parameters with longer paths e.g. from 'c:/users/name/a/b' to
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { KeymanFileTypes } from "@keymanapp/common-types";
|
||||
import { CompilerCallbacks, KeymanDeveloperProject, KPJFileReader } from "@keymanapp/developer-utils";
|
||||
import { CompilerCallbacks, KeymanDeveloperProject, ProjectLoader } from "@keymanapp/developer-utils";
|
||||
import { InfrastructureMessages } from "../messages/infrastructureMessages.js";
|
||||
|
||||
export const isProject = (filename: string): boolean =>
|
||||
|
|
@ -26,7 +26,7 @@ export async function loadProject(infile: string, callbacks: CompilerCallbacks)
|
|||
}
|
||||
|
||||
const project = callbacks.fs.existsSync(infile) ?
|
||||
await loadProjectFromFile(infile, callbacks) :
|
||||
await ProjectLoader.loadProjectFromFile(infile, callbacks) :
|
||||
await loadDefaultProjectFromFolder(infile, callbacks);
|
||||
|
||||
return project;
|
||||
|
|
@ -42,21 +42,3 @@ async function loadDefaultProjectFromFolder(infile: string, callbacks: CompilerC
|
|||
return project;
|
||||
}
|
||||
|
||||
async function loadProjectFromFile(infile: string, callbacks: CompilerCallbacks): Promise<KeymanDeveloperProject> {
|
||||
const kpjData = await callbacks.fsAsync.readFile(infile);
|
||||
const reader = new KPJFileReader(callbacks);
|
||||
let kpj = null;
|
||||
try {
|
||||
kpj = reader.read(kpjData);
|
||||
if(kpj.KeymanDeveloperProject?.Options?.Version && kpj.KeymanDeveloperProject.Options.Version != "1.0" && kpj.KeymanDeveloperProject.Options.Version != "2.0") {
|
||||
callbacks.reportMessage(InfrastructureMessages.Error_UnsupportedProjectVersion({version: kpj.KeymanDeveloperProject.Options.Version}));
|
||||
return null;
|
||||
}
|
||||
reader.validate(kpj);
|
||||
} catch(e) {
|
||||
callbacks.reportMessage(InfrastructureMessages.Error_InvalidProjectFile({message: (e??'').toString()}));
|
||||
return null;
|
||||
}
|
||||
const project = await reader.transform(infile, kpj);
|
||||
return project;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { KeymanSentry } from "@keymanapp/developer-utils";
|
||||
import { KeymanSentry } from './KeymanSentry.js';
|
||||
|
||||
/**
|
||||
* Exit codes defined in <sysexits.h>:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
|
||||
import { clearOptions } from '@keymanapp/developer-utils';
|
||||
import { clearOptions } from '../src/util/options.js';
|
||||
import { assert } from 'chai';
|
||||
import 'mocha';
|
||||
import { BuildProject } from '../src/commands/buildClasses/BuildProject.js';
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import { NodeCompilerCallbacks } from '../src/util/NodeCompilerCallbacks.js';
|
|||
import { KeymanFileTypes } from '@keymanapp/common-types';
|
||||
import { unitTestEndpoints } from '../src/commands/build.js';
|
||||
import { KmnCompilerMessages } from '@keymanapp/kmc-kmn';
|
||||
import { clearOptions } from '@keymanapp/developer-utils';
|
||||
import { clearOptions } from '../src/util/options.js';
|
||||
import { loadProject } from '../src/util/projectLoader.js';
|
||||
import { CompilerErrorNamespace, CompilerEvent, defaultCompilerOptions, CompilerOptions} from '@keymanapp/developer-utils';
|
||||
import { CompilerErrorNamespace, CompilerEvent, defaultCompilerOptions, CompilerOptions, DeveloperUtilsMessages} from '@keymanapp/developer-utils';
|
||||
import { analyzeUnitTestEndpoints } from '../src/commands/analyze.js';
|
||||
import { BuildKeyboardInfo } from '../src/commands/buildClasses/BuildKeyboardInfo.js';
|
||||
import { BuildModelInfo } from '../src/commands/buildClasses/BuildModelInfo.js';
|
||||
|
|
@ -71,12 +71,12 @@ describe('InfrastructureMessages', function () {
|
|||
'ERROR_OutFileNotValidForProjects not generated, instead got: '+JSON.stringify(ncb.messages,null,2));
|
||||
});
|
||||
|
||||
// ERROR_InvalidProjectFile
|
||||
// ERROR_InvalidProjectFile - test stays here for now though referencing developer-messages
|
||||
|
||||
it('should generate ERROR_InvalidProjectFile if a project file is invalid', async function() {
|
||||
const ncb = new NodeCompilerCallbacks({logLevel: 'silent'});
|
||||
await unitTestEndpoints.build(makePathToFixture('invalid-projects', 'error_invalid_project_file.kpj'), null, ncb, {});
|
||||
assert.isTrue(ncb.hasMessage(InfrastructureMessages.ERROR_InvalidProjectFile),
|
||||
assert.isTrue(ncb.hasMessage(DeveloperUtilsMessages.ERROR_InvalidProjectFile),
|
||||
'ERROR_InvalidProjectFile not generated, instead got: '+JSON.stringify(ncb.messages,null,2));
|
||||
});
|
||||
|
||||
|
|
@ -202,14 +202,14 @@ describe('InfrastructureMessages', function () {
|
|||
assertMessagesEqual(ncb.messages, expectedMessages);
|
||||
});
|
||||
|
||||
// ERROR_UnsupportedProjectVersion
|
||||
// ERROR_UnsupportedProjectVersion (test stays here for now though referencing developer-utils)
|
||||
|
||||
it('should generate ERROR_UnsupportedProjectVersion if a project file with an unsupported version is loaded', async function() {
|
||||
const ncb = new NodeCompilerCallbacks({logLevel: 'silent'});
|
||||
const filename = makePathToFixture('invalid-projects', 'error_unsupported_project_version.kpj');
|
||||
const expectedMessages = [
|
||||
InfrastructureMessages.INFO_BuildingFile,
|
||||
InfrastructureMessages.ERROR_UnsupportedProjectVersion,
|
||||
DeveloperUtilsMessages.ERROR_UnsupportedProjectVersion,
|
||||
InfrastructureMessages.INFO_ProjectNotBuiltSuccessfully
|
||||
];
|
||||
await unitTestEndpoints.build(filename, null, ncb, {compilerWarningsAsErrors: true});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import 'mocha';
|
|||
import { BuildProject } from '../src/commands/buildClasses/BuildProject.js';
|
||||
import { makePathToFixture } from './helpers/index.js';
|
||||
import { InfrastructureMessages } from '../src/messages/infrastructureMessages.js';
|
||||
import { clearOptions } from '@keymanapp/developer-utils';
|
||||
import { clearOptions } from '../src/util/options.js';
|
||||
|
||||
const callbacks = new TestCompilerCallbacks();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// TODO: this is duplicated in kmc!
|
||||
import Sentry from "@sentry/node";
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { getOption } from "./options.js";
|
||||
|
|
@ -5,12 +5,13 @@ import chalk from 'chalk';
|
|||
import express from 'express';
|
||||
import multer from 'multer';
|
||||
import * as ws from 'ws';
|
||||
import { KeymanSentry, loadOptions } from '@keymanapp/developer-utils';
|
||||
import { KeymanSentry } from './KeymanSentry.js';
|
||||
import { configuration } from './config.js';
|
||||
import { environment } from './environment.js';
|
||||
import setupRoutes from './routes.js';
|
||||
import { shutdown } from './shutdown.js';
|
||||
import { initTray } from './tray.js';
|
||||
import { loadOptions } from './options.js';
|
||||
|
||||
const options = {
|
||||
ngrokLog: false, // Set this to true if you need to see ngrok logs in the console
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { KeymanSentry } from '@keymanapp/developer-utils';
|
||||
import { KeymanSentry } from './KeymanSentry.js';
|
||||
import { readFileSync, existsSync } from 'fs';
|
||||
|
||||
export function loadJsonFile(filename: string): any {
|
||||
|
|
|
|||
96
developer/src/server/src/options.ts
Normal file
96
developer/src/server/src/options.ts
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
// TODO: this is duplicated in kmc
|
||||
import * as os from 'node:os';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export interface KeymanDeveloperOptions {
|
||||
"use tab char"?: boolean;
|
||||
"link font sizes"?: boolean;
|
||||
"indent size"?: number;
|
||||
"use old debugger"?: boolean;
|
||||
"editor theme"?: string;
|
||||
"debugger break when exiting line"?: boolean;
|
||||
"debugger single step after break"?: boolean;
|
||||
"debugger show store offset"?: boolean;
|
||||
"debugger recompile with debug info"?: boolean;
|
||||
"debugger auto reset before compilng"?: boolean;
|
||||
"auto save before compiling"?: boolean;
|
||||
"osk auto save before importing"?: boolean;
|
||||
"web host port"?: number;
|
||||
"server keep alive"?: boolean;
|
||||
"server use local addresses"?: boolean;
|
||||
"server ngrok token"?: string;
|
||||
"server ngrok region"?: string;
|
||||
"server use ngrok"?: boolean;
|
||||
"server show console window"?: boolean;
|
||||
"char map disable database lookups"?: boolean;
|
||||
"char map auto lookup"?: boolean;
|
||||
"open keyboard files in source view"?: boolean;
|
||||
"display theme"?: string;
|
||||
"external editor path"?: string;
|
||||
"smtp server"?: string;
|
||||
"test email addresses"?: string;
|
||||
"web ladder length"?: number;
|
||||
"default project path"?: string;
|
||||
"automatically report errors"?: boolean;
|
||||
"automatically report usage"?: boolean;
|
||||
"toolbar visible"?: boolean;
|
||||
"active project"?: string;
|
||||
"prompt to upgrade projects"?: boolean;
|
||||
};
|
||||
|
||||
type KeymanDeveloperOption = keyof KeymanDeveloperOptions;
|
||||
|
||||
// Default has no options set, and unit tests will use the defaults (won't call
|
||||
// `loadOptions()`)
|
||||
let options: KeymanDeveloperOptions = {};
|
||||
|
||||
// We only load the options from disk once on first use
|
||||
let optionsLoaded = false;
|
||||
|
||||
export async function loadOptions(): Promise<KeymanDeveloperOptions> {
|
||||
if(optionsLoaded) {
|
||||
return options;
|
||||
}
|
||||
|
||||
options = {};
|
||||
try {
|
||||
const optionsFile = path.join(os.homedir(), '.keymandeveloper', 'options.json');
|
||||
if(fs.existsSync(optionsFile)) {
|
||||
for(let i = 0; i < 5; i++) {
|
||||
try {
|
||||
const data = JSON.parse(fs.readFileSync(optionsFile, 'utf-8'));
|
||||
if(typeof data == 'object') {
|
||||
options = data;
|
||||
}
|
||||
break;
|
||||
} catch(e) {
|
||||
if(e?.code == 'EBUSY') {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
} else {
|
||||
// give up, nothing to report here
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
// Nothing to report here, sadly -- because we cannot rely on Sentry at this
|
||||
// low level.
|
||||
options = {};
|
||||
}
|
||||
optionsLoaded = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
export function getOption<T extends KeymanDeveloperOption>(valueName: T, defaultValue: KeymanDeveloperOptions[T]): KeymanDeveloperOptions[T] {
|
||||
return options[valueName] ?? defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* unit tests will clear options before running, for consistency
|
||||
*/
|
||||
export function clearOptions() {
|
||||
options = {};
|
||||
optionsLoaded = true;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { KeymanSentry } from '@keymanapp/developer-utils';
|
||||
import { KeymanSentry } from './KeymanSentry.js';
|
||||
|
||||
export async function shutdown(code?: number): Promise<never> {
|
||||
await KeymanSentry.close();
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ LPKMX_KEYBOARD CopyKeyboard(PKMX_BYTE bufp, PKMX_BYTE base) {
|
|||
* @return pointer to the keyboard
|
||||
*/
|
||||
LPKMX_KEYBOARD KMX_FixupKeyboard(PKMX_BYTE bufp, PKMX_BYTE base, KMX_DWORD dwFileSize) {
|
||||
UNREFERENCED_PARAMETER(dwFileSize);
|
||||
// UNREFERENCED_PARAMETER(dwFileSize);
|
||||
|
||||
KMX_DWORD i, j;
|
||||
PCOMP_KEYBOARD ckbp = (PCOMP_KEYBOARD)base;
|
||||
|
|
@ -369,9 +369,9 @@ LPKMX_KEYBOARD KMX_FixupKeyboard(PKMX_BYTE bufp, PKMX_BYTE base, KMX_DWORD dwFil
|
|||
for (gp = kbp->dpGroupArray, cgp = (PCOMP_GROUP)gp, i = 0; i < kbp->cxGroupArray; i++, gp++, cgp++) {
|
||||
gp->dpName = KMX_StringOffset(base, cgp->dpName);
|
||||
gp->dpKeyArray = (LPKMX_KEY)(base + cgp->dpKeyArray);
|
||||
if (cgp->dpMatch != NULL)
|
||||
if (cgp->dpMatch != 0)
|
||||
gp->dpMatch = (PKMX_WCHAR)(base + cgp->dpMatch);
|
||||
if (cgp->dpNoMatch != NULL)
|
||||
if (cgp->dpNoMatch != 0)
|
||||
gp->dpNoMatch = (PKMX_WCHAR)(base + cgp->dpNoMatch);
|
||||
|
||||
for (kp = gp->dpKeyArray, ckp = (PCOMP_KEY)kp, j = 0; j < gp->cxKeyArray; j++, kp++, ckp++) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
} from '@actions/core';
|
||||
|
||||
import { GitHub } from '@actions/github';
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { gt } from 'semver';
|
||||
import { reportHistory } from './reportHistory.js';
|
||||
import { spawnChild } from './util/spawnAwait.js';
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// incrementVersion
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
||||
export const incrementVersion = () => {
|
||||
// 1.
|
||||
// 1.
|
||||
const version = readFileSync('./VERSION.md', 'utf8');
|
||||
const triplet = version.split('.');
|
||||
const patch = parseInt(triplet[2], 10) + 1;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { sendCommentToPullRequestAndRelatedIssues, fixupHistory } from './fixupH
|
|||
import { incrementVersion } from './incrementVersion.js';
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import { readFileSync } from 'fs';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { reportHistory } from './reportHistory.js';
|
||||
|
||||
const argv = await yargs(hideBin(process.argv))
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import {
|
|||
default as CloudQueryEngine
|
||||
} from './cloud/queryEngine.js';
|
||||
|
||||
import fs from 'fs';
|
||||
import https from 'https';
|
||||
import vm from 'vm';
|
||||
import fs from 'node:fs';
|
||||
import https from 'node:https';
|
||||
import vm from 'node:vm';
|
||||
|
||||
export default class NodeCloudRequester implements CloudRequesterInterface {
|
||||
private static QUERY_SEED = 1;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
// Original version found at: https://github.com/eddieantonio/unicode-default-word-boundary/blob/master/libexec/compile-word-break.js
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
|
|
|||
|
|
@ -3,17 +3,17 @@
|
|||
/// <reference path="../worker-interface.d.ts" />
|
||||
|
||||
// Defines types related to Node workers.
|
||||
import * as worker from 'worker_threads';
|
||||
import { Buffer } from 'buffer';
|
||||
import { URL } from 'url';
|
||||
import * as worker from 'node:worker_threads';
|
||||
import { Buffer } from 'node:buffer';
|
||||
import { URL } from 'node:url';
|
||||
|
||||
/**
|
||||
* Defines mappings from Node Worker signatures to WebWorker signatures
|
||||
*/
|
||||
const nodeWorkerToWebWorkerMappingSource = `
|
||||
import { parentPort } from 'worker_threads';
|
||||
import fs from 'fs';
|
||||
import vm from 'vm';
|
||||
import { parentPort } from 'node:worker_threads';
|
||||
import fs from 'node:fs';
|
||||
import vm from 'node:vm';
|
||||
|
||||
function postMessage(...args) {
|
||||
parentPort.postMessage.call(parentPort, args);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import SourcemapRemapper from "@keymanapp/sourcemap-path-remapper"
|
||||
import convertSourceMap from 'convert-source-map'; // Transforms sourcemaps among various common formats.
|
||||
// Base64, stringified-JSON, end-of-file comment...
|
||||
import fs from 'fs';
|
||||
import fs from 'node:fs';
|
||||
|
||||
function displayHelp() {
|
||||
console.log("KeymanWeb's sourcemap-cleansing tool. This tool is designed to produce clean filepaths");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue