consolidate dictionary lookup of spellchecker and thesaurus, prepare builtin distribution of dictionaries

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@34540 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Stephan Witt 2010-05-29 14:36:51 +00:00
parent c1bde420f8
commit 042e8bb4d0
5 changed files with 466 additions and 218 deletions

View File

@ -17,6 +17,9 @@ AC_DEFUN([CHECK_WITH_ASPELL],
AC_MSG_RESULT(yes)
AC_DEFINE(USE_ASPELL, 1, [Define as 1 to use the aspell library])
lyx_flags="$lyx_flags use-aspell"
### Check for aspell framework name
LYX_WITH_DIR([aspell-framework], [name of aspell framework],aspell_framework, [])
AC_DEFINE_UNQUOTED([ASPELL_FRAMEWORK], "${lyx_cv_aspell_framework}", [Define as name of aspell framework])
else
AC_MSG_RESULT(no)
fi
@ -74,16 +77,6 @@ AC_DEFUN([LYX_CHECK_SPELL_ENGINES],
CHECK_WITH_ASPELL
AM_CONDITIONAL(USE_ASPELL, $lyx_use_aspell)
if $lyx_use_aspell ; then
### Check for aspell framework name
LYX_WITH_DIR([aspell-framework],[name of aspell framework],aspell_framework, NONE)
if ! test "x${lyx_cv_aspell_framework}" = xNONE; then
AC_DEFINE_UNQUOTED([ASPELL_FRAMEWORK], "${lyx_cv_aspell_framework}")
else
AC_DEFINE(ASPELL_FRAMEWORK, [""], [Define as name of aspell framework])
fi
fi
CHECK_WITH_ENCHANT
AM_CONDITIONAL(USE_ENCHANT, $lyx_use_enchant)

View File

@ -9,12 +9,27 @@
# Prerequisite:
# * a decent checkout of LyX sources (probably you have it already)
# * Qt4 - build with shared or static libraries for the used platforms (i386 and ppc)
# * Qt4 - build with shared or static libraries for the used platforms (default: i386 and ppc)
# or - an unpacked source tree of Qt4 in $QT4SOURCEDIR or in the sibling directory (variable Qt4SourceVersion)
# * for aspell support:
# the aspell sources placed in a sibling directory (variable ASpellSourceVersion)
# * for hunspell support:
# the hunspell sources placed in a sibling directory (variable HunSpellSourceVersion)
# * for dictionary deployment:
# - aspell: the dictionary files of macports (in /opt/local/share/aspell and /opt/local/lib/aspell-0.60)
# - hunspell: the dictionary files in the sibling directory Dictionaries/dict
# - mythes: the data and idx files in the sibling directory Dictionaries/thes
ConfigureOptions="--enable-warnings --enable-optimization=-Os --with-included-gettext"
dict_deployment="yes"
LyXConfigureOptions="--enable-warnings --enable-optimization=-Os --with-included-gettext"
AspellConfigureOptions="--enable-warnings --disable-nls --enable-compile-in-filters --disable-pspell-compatibility"
HunspellConfigureOptions="--with-warnings --disable-nls --with-included-gettext --disable-static"
Qt4ConfigureOptions="-opensource -silent -shared -release -fast -no-exceptions"
Qt4ConfigureOptions="${Qt4ConfigureOptions} -no-webkit -no-qt3support -no-javascript-jit -no-dbus"
Qt4ConfigureOptions="${Qt4ConfigureOptions} -nomake examples -nomake demos -nomake docs -nomake tools"
aspell_deployment="yes"
hunspell_deployment="yes"
thesaurus_deployment="yes"
qt4_deployment="yes"
MACOSX_DEPLOYMENT_TARGET="10.4" # Tiger support is default
@ -22,15 +37,15 @@ usage() {
echo Build script for LyX on Mac OS X
echo
echo Optional arguments:
echo " --tiger-support=yes|no ....." default yes
echo " --dict-deployment=yes|no ..." default yes
echo " --aspell-deployment=yes|no ." default yes
echo " --qt4-deployment=yes|no ...." default yes
echo " --with-macosx-target=TARGET " default 10.4 "(Tiger)"
echo " --with-arch=ARCH ..........." default ppc,i386
echo " --with-build-path=PATH ....." default \${lyx-src-dir}/../lyx-build
echo " --with-dmg-location=PATH ..." default \${build-path}
echo
echo "All other arguments with -- are passed to configure"
echo "including the defaults: ${ConfigureOptions}"
echo "including the defaults: ${LyXConfigureOptions}"
echo
exit 0
}
@ -41,13 +56,20 @@ while [ $# -gt 0 ]; do
QTDIR=`echo ${1}|cut -d= -f2`
shift
;;
--tiger-support=[Nn][Oo])
MACOSX_DEPLOYMENT_TARGET=""
MYCFLAGS=""
--with-macosx-target=*)
MACOSX_DEPLOYMENT_TARGET=`echo ${1}|cut -d= -f2`
shift
;;
--dict-deployment=*)
dict_deployment=`echo ${1}|cut -d= -f2`
--aspell-deployment=*)
aspell_deployment=`echo ${1}|cut -d= -f2`
shift
;;
--hunspell-deployment=*)
hunspell_deployment=`echo ${1}|cut -d= -f2`
shift
;;
--thesaurus-deployment=*)
thesaurus_deployment=`echo ${1}|cut -d= -f2`
shift
;;
--qt4-deployment=*)
@ -70,8 +92,18 @@ while [ $# -gt 0 ]; do
--help)
usage
;;
--without-aspell)
LyXConfigureOptions="${LyXConfigureOptions} ${1}"
aspell_deployment="no"
shift
;;
--without-hunspell)
LyXConfigureOptions="${LyXConfigureOptions} ${1}"
hunspell_deployment="no"
shift
;;
--*)
ConfigureOptions="${ConfigureOptions} ${1}"
LyXConfigureOptions="${LyXConfigureOptions} ${1}"
shift
;;
*)
@ -90,6 +122,9 @@ done
QtInstallDir=${QTDIR:-"/opt/qt4"}
QtFrameworkVersion="4"
ASpellSourceVersion="aspell-0.60.6"
HunSpellSourceVersion="hunspell-1.2.9"
Qt4SourceVersion="qt-everywhere-opensource-src-4.6.2"
ARCH_LIST=${ARCH_LIST:-"ppc i386"}
strip="-strip"
@ -119,11 +154,16 @@ LyxBuildDir=${LyxBuildDir:-`dirname "${LyxSourceDir}"`/lyx-build}
DMGLocation=${DMGLocation:-"${LyxBuildDir}"}
ASpellSourceDir=${ASPELLDIR:-`dirname "${LyxSourceDir}"`/${ASpellSourceVersion}}
ASpellInstallDir=${ASpellInstallDir:-"${LyxBuildDir}"/${ASpellSourceVersion}.lib}
ASpellInstallDir=${ASpellInstallDir:-"${LyxBuildDir}"/SpellChecker.lib}
HunSpellSourceDir=${HUNSPELLDIR:-`dirname "${LyxSourceDir}"`/${HunSpellSourceVersion}}
HunSpellInstallDir=${HunSpellInstallDir:-"${LyxBuildDir}"/SpellChecker.lib}
Qt4SourceDir=${QT4SOURCEDIR:-`dirname "${LyxSourceDir}"`/${Qt4SourceVersion}}
Qt4BuildDir="${LyxBuildDir}/qt4-build"
DictionarySourceDir=${DICTIONARYDIR:-`dirname "${LyxSourceDir}"`/Dictionaries}
ASpellInstallHdr="${ASpellInstallDir}/include/aspell.h"
HunSpellInstallHdr="${HunSpellInstallDir}/include/hunspell/hunspell.h"
if [ ! -f "${LyxSourceDir}"/configure ]; then
( cd "${LyxSourceDir}" && sh autogen.sh )
fi
if [ -z "${LyXVersion}" ]; then
LyXVersion=`grep AC_INIT "${LyxSourceDir}"/configure.ac | cut -d, -f2 | tr -d " ()"`
fi
@ -151,9 +191,11 @@ BuildSystem=`"${LyxSourceDir}/config/config.guess"`
HostSystem_i386="i686-apple-darwin8"
HostSystem_ppc="powerpc-apple-darwin8"
DMGNAME="${LyxBase}-Uncompressed.dmg"
# don't change order here...
QtLibraries="QtSvg QtXml QtGui QtNetwork QtCore"
DMGNAME="${LyxBase}"
DMGSIZE="550m"
COMPRESSEDDMGNAME="${LyxBase}.dmg"
BACKGROUND="${LyxAppDir}.app/Contents/Resources/images/banner.png"
# Check for existing SDKs
@ -184,7 +226,97 @@ case "$SDKs" in
esac
MYCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET}"
if [ -d "${ASpellSourceDir}" -a ! -d "${ASpellInstallDir}" ]; then
if [ -d "${Qt4SourceDir}" -a ! -d "${Qt4BuildDir}" ]; then
echo Build Qt4 library ${Qt4SourceDir}
(
mkdir -p "${Qt4BuildDir}" && cd "${Qt4BuildDir}"
for arch in ${ARCH_LIST} ; do
ARCHS="${ARCHS} -arch ${arch}"
done
echo configure options:
echo ${Qt4ConfigureOptions} ${ARCHS} -prefix "${QtInstallDir}"
echo yes | "${Qt4SourceDir}"/configure ${Qt4ConfigureOptions} ${ARCHS} -prefix "${QtInstallDir}"
make && make install
)
cd "${QtInstallDir}" && (
mkdir -p include
cd include
for libnm in ${QtLibraries} ; do
test -d ${libnm} -o -L ${libnm} || ln -s ../lib/${libnm}.framework/Headers ${libnm}
done
)
fi
if [ -d "${HunSpellSourceDir}" -a ! -f "${HunSpellInstallHdr}" ]; then
# we have a private HunSpell source tree at hand...
# so let's build and install it
if [ -z "${HunSpellVersion}" ]; then
HunSpellVersion=`grep AC_INIT "${HunSpellSourceDir}"/configure.ac | cut -d, -f2|tr -d " ()"`
fi
HunSpellName="Hunspell"
HunSpellBase="${HunSpellName}-${HunSpellVersion}"
echo Build hunspell library ${HunSpellBase}
echo configure options:
echo --prefix="${HunSpellInstallDir}" ${HunspellConfigureOptions}
cd "${HunSpellSourceDir}"
# ----------------------------------------
# Build HunSpell for different architectures
# ----------------------------------------
FILE_LIST="libhunspell-1.2.0.dylib"
for arch in ${ARCH_LIST} ; do
make distclean
CPPFLAGS=" -arch ${arch} ${MYCFLAGS}"; export CPPFLAGS
LDFLAGS=" -arch ${arch}"; export LDFLAGS
HOSTSYSTEM=`eval "echo \\$HostSystem_$arch"`
"${HunSpellSourceDir}/configure"\
--prefix="${HunSpellInstallDir}"\
${HunspellConfigureOptions}
#--host="${HOSTSYSTEM}" ${BuildSystem:+"--build=${BuildSystem}"}
make && make install${strip}
for file in ${FILE_LIST} ; do
if [ -f "${HunSpellInstallDir}"/lib/${file} ]; then
mv "${HunSpellInstallDir}"/lib/${file}\
"${HunSpellInstallDir}"/lib/${file}-${arch}
else
echo Cannot build and install HunSpell for ${arch}.
exit 1
fi
done
done
# -------------------------
# Create universal binaries
# -------------------------
for file in ${FILE_LIST} ; do
OBJ_LIST=
for arch in ${ARCH_LIST} ; do
OBJ_LIST="${OBJ_LIST} lib/${file}-${arch}"
done
(
cd "${HunSpellInstallDir}"
lipo -create ${OBJ_LIST} -o lib/${file}
# check for the "missing link"...
test -f lib/libhunspell.dylib || (cd lib ; ln -s libhunspell-1.2.dylib libhunspell.dylib)
)
done
# --------
# Clean up
# --------
for arch in ${ARCH_LIST} ; do
rm -f "${HunSpellInstallDir}"/lib/*-${arch}
done
fi
#exit 0
if [ -d "${ASpellSourceDir}" -a ! -f "${ASpellInstallHdr}" -a "yes" = "${aspell_deployment}" ]; then
# we have a private ASpell source tree at hand...
# so let's build and install it
if [ -z "${ASpellVersion}" ]; then
@ -195,27 +327,26 @@ if [ -d "${ASpellSourceDir}" -a ! -d "${ASpellInstallDir}" ]; then
ASpellBase="${ASpellName}-${ASpellVersion}"
echo Build aspell library ${ASpellBase}
# Clear Output
if [ -n "${ASpellLibZip}" -a -f "${ASpellLibZip}" ]; then rm "${ASpellLibZip}"; fi
if [ -d "${ASpellInstallDir}" ]; then rm -r "${ASpellInstallDir}"; fi
echo configure options:
echo --prefix="${ASpellInstallDir}" ${AspellConfigureOptions}
# ASpell builds inplace only :(
cd "${ASpellSourceDir}" && make distclean
cd "${ASpellSourceDir}"
# ----------------------------------------
# Build ASpell for different architectures
# ----------------------------------------
FILE_LIST="libaspell.15.dylib libpspell.15.dylib"
FILE_LIST="libaspell.15.dylib"
for arch in ${ARCH_LIST} ; do
CPPFLAGS="${SDKROOT:+-isysroot ${SDKROOT}} -arch ${arch} ${MYCFLAGS}"; export CPPFLAGS
LDFLAGS="${SDKROOT:+-isysroot ${SDKROOT}} -arch ${arch}"; export LDFLAGS
make distclean
CPPFLAGS=" -arch ${arch} ${MYCFLAGS}"; export CPPFLAGS
LDFLAGS=" -arch ${arch}"; export LDFLAGS
HOSTSYSTEM=`eval "echo \\$HostSystem_$arch"`
"${ASpellSourceDir}/configure"\
--prefix="${ASpellInstallDir}"\
${ConfigureOptions}\
--host="${HOSTSYSTEM}" ${BuildSystem:+"--build=${BuildSystem}"} --enable-build-type=rel
${AspellConfigureOptions}
#--host="${HOSTSYSTEM}" ${BuildSystem:+"--build=${BuildSystem}"}
make && make install${strip}
for file in ${FILE_LIST} ; do
if [ -f "${ASpellInstallDir}"/lib/${file} ]; then
@ -226,7 +357,6 @@ if [ -d "${ASpellSourceDir}" -a ! -d "${ASpellInstallDir}" ]; then
exit 1
fi
done
make distclean
done
# -------------------------
# Create universal binaries
@ -253,6 +383,10 @@ framework_name() {
echo "Frameworks/${1}.framework"
}
if [ ! -f "${LyxSourceDir}"/configure ]; then
( cd "${LyxSourceDir}" && sh autogen.sh )
fi
FILE_LIST="lyx lyxclient tex2lyx"
BUNDLE_PATH="Contents/MacOS"
LYX_BUNDLE_PATH="${LyxAppPrefix}/${BUNDLE_PATH}"
@ -265,14 +399,24 @@ build_lyx() {
# Build LyX for different architectures
# -------------------------------------
if [ -d "${ASpellInstallDir}" ]; then
if [ -d "${ASpellInstallDir}" -a "yes" = "${aspell_deployment}" ]; then
ASpellFramework=`framework_name Aspell`
ASpellFramework=`basename "${ASpellFramework}"`
ConfigureOptions="${ConfigureOptions} --with-extra-inc=${ASpellInstallDir}/include"
ConfigureOptions="${ConfigureOptions} --with-extra-lib=${ASpellInstallDir}/lib"
ConfigureOptions="${ConfigureOptions} --with-aspell-framework=${ASpellFramework}"
ConfigureExtraInc="--with-extra-inc=${ASpellInstallDir}/include"
ConfigureExtraLib="--with-extra-lib=${ASpellInstallDir}/lib"
LyXConfigureOptions="${LyXConfigureOptions} --with-aspell-framework=${ASpellFramework}"
fi
if [ -d "${HunSpellInstallDir}" -a "yes" = "${hunspell_deployment}" ]; then
HunSpellFramework=`framework_name Hunspell`
HunSpellFramework=`basename "${HunSpellFramework}"`
ConfigureExtraInc="--with-extra-inc=${HunSpellInstallDir}/include"
ConfigureExtraLib="--with-extra-lib=${HunSpellInstallDir}/lib"
# LyXConfigureOptions="${LyXConfigureOptions} --with-hunspell-framework=${HunSpellFramework}"
fi
LyXConfigureOptions="${LyXConfigureOptions} ${ConfigureExtraInc}"
LyXConfigureOptions="${LyXConfigureOptions} ${ConfigureExtraLib}"
for arch in ${ARCH_LIST} ; do
if [ -d "${LyxBuildDir}" ]; then rm -r "${LyxBuildDir}"; fi
@ -284,11 +428,11 @@ build_lyx() {
echo LDFLAGS="${LDFLAGS}"
echo CPPFLAGS="${CPPFLAGS}"
echo CONFIGURE_OPTIONS="${ConfigureOptions}"
echo CONFIGURE_OPTIONS="${LyXConfigureOptions}"
"${LyxSourceDir}/configure"\
--prefix="${LyxAppPrefix}" --with-version-suffix="-${LyXVersion}"\
${QtInstallDir:+"--with-qt4-dir=${QtInstallDir}"} \
${ConfigureOptions}\
${LyXConfigureOptions}\
--host="${HOSTSYSTEM}" --build="${BuildSystem}" --enable-build-type=rel
make && make install${strip}
for file in ${FILE_LIST} ; do
@ -347,8 +491,7 @@ EOF
cp -p "${libname}" "${condir}/PlugIns/${dirname}"
done
fi
# don't change order here...
for libnm in QtSvg QtXml QtGui QtNetwork QtCore ; do
for libnm in ${QtLibraries} ; do
fwdir=`framework_name "$libnm"`
dirname=`basename "${fwdir}"`
test -d "${condir}/${fwdir}" || (
@ -394,9 +537,12 @@ convert_universal() {
if [ -n "${OBJ_LIST}" ]; then
lipo -create ${OBJ_LIST} -o "${BUNDLE_PATH}/${file}"
fi
if [ -d "${ASpellInstallDir}" ]; then
if [ -d "${ASpellInstallDir}" -a "yes" = "${aspell_deployment}" ]; then
private_framework Aspell "${ASpellInstallDir}/lib/libaspell.15.dylib" "${LYX_BUNDLE_PATH}/${file}"
fi
if [ -d "${HunSpellInstallDir}" -a "yes" = "${hunspell_deployment}" ]; then
private_framework Hunspell "${HunSpellInstallDir}/lib/libhunspell-1.2.0.dylib" "${LYX_BUNDLE_PATH}/${file}"
fi
if [ -d "${QtInstallDir}/lib/QtCore.framework/Versions/${QtFrameworkVersion}" -a "yes" = "${qt4_deployment}" ]; then
deploy_qtlibs "${LYX_BUNDLE_PATH}/${file}"
fi
@ -414,7 +560,7 @@ convert_universal() {
}
copy_dictionaries() {
if [ -d "${ASpellInstallDir}" -a "yes" = "${dict_deployment}" ]; then
if [ -d "${ASpellInstallDir}" -a "yes" = "${aspell_deployment}" ]; then
ASpellFramework=`framework_name Aspell`
ASpellResources="${LyxAppPrefix}/Contents/${ASpellFramework}/Resources"
# try to reuse macports dictionaries for now
@ -424,6 +570,16 @@ copy_dictionaries() {
cp -p -r "${ASpellInstallDir}/lib/aspell-0.60" "${ASpellResources}"/data
cp -p -r "${ASpellInstallDir}/share/aspell" "${ASpellResources}"/dict
fi
if [ -d "${HunSpellInstallDir}" -a "yes" = "${hunspell_deployment}" ]; then
HunSpellResources="${LyxAppPrefix}/Contents/Resources"
if [ -d "${DictionarySourceDir}" ]; then
cp -p -r "${DictionarySourceDir}/dict" "${HunSpellResources}"
fi
fi
if [ -d "${DictionarySourceDir}" -a "yes" = "${thesaurus_deployment}" ]; then
MyThesResources="${LyxAppPrefix}/Contents/Resources"
cp -p -r "${DictionarySourceDir}/thes" "${MyThesResources}"
fi
}
function set_bundle_display_options() {
@ -464,38 +620,37 @@ function make_dmg() {
BG_H=`echo ${BGSIZE} | awk '{h = $2 + 20 ;print h }'`
BG_Y=`echo ${BGSIZE} | awk '{y = $2 - 60 ;print y }'`
rm -f ${DMGNAME}
rm -f ${COMPRESSEDDMGNAME}
rm -f "${DMGNAME}.sparseimage" "${DMGNAME}.dmg"
hdiutil create -type SPARSE -size ${DMGSIZE:-"250m"} -fs HFS+ -volname "${LyxBase}" "${DMGNAME}"
# Unmount currently mounted disk image
test -d /Volumes/"${LyxBase}" && umount /Volumes/"${LyxBase}"
# Mount the disk image
hdiutil attach ${DMGNAME}.sparseimage
hdiutil attach "${DMGNAME}.sparseimage"
# Obtain device information
DEVS=$(hdiutil attach ${DMGNAME}.sparseimage | cut -f 1)
DEVS=$(hdiutil attach "${DMGNAME}.sparseimage" | cut -f 1)
DEV=$(echo $DEVS | cut -f 1 -d ' ')
VOLUME=$(mount |grep ${DEV} | cut -f 3 -d ' ')
# copy in the application bundle
cp -Rp ${LyxAppDir}.app ${VOLUME}/${LyxName}.app
cp -Rp "${LyxAppDir}.app" "${VOLUME}/${LyxName}.app"
# copy in background image
mkdir -p ${VOLUME}/Pictures
cp ${BACKGROUND} ${VOLUME}/Pictures/background.png
mkdir -p "${VOLUME}/Pictures"
cp "${BACKGROUND}" "${VOLUME}/Pictures/background.png"
# symlink applications
ln -s /Applications/ ${VOLUME}/Applications
set_bundle_display_options ${VOLUME} ${BG_W} ${BG_H} ${BG_Y}
mv ${VOLUME}/Pictures ${VOLUME}/.Pictures
ln -s /Applications/ "${VOLUME}"/Applications
set_bundle_display_options "${VOLUME}" ${BG_W} ${BG_H} ${BG_Y}
mv "${VOLUME}/Pictures" "${VOLUME}/.Pictures"
# Unmount the disk image
hdiutil detach ${DEV}
# Convert the disk image to read-only
hdiutil convert ${DMGNAME}.sparseimage -format UDBZ -o ${COMPRESSEDDMGNAME}
rm -f ${DMGNAME}.sparseimage
hdiutil convert "${DMGNAME}.sparseimage" -format UDBZ -o "${DMGNAME}.dmg"
rm -f "${DMGNAME}.sparseimage"
}
build_lyx
@ -510,4 +665,15 @@ test -n "${LyxAppZip}" && (
cd "${LyxAppPrefix}" && zip -r "${LyxAppZip}" .
)
test -n "${DMGLocation}" && make_dmg "${DMGLocation}"
test -n "${DMGLocation}" && (
make_dmg "${DMGLocation}"
if [ -d "${QtInstallDir}/lib/QtCore.framework/Versions/${QtFrameworkVersion}" -a "yes" = "${qt4_deployment}" ]; then
rm -f "${DMGLocation}/${DMGNAME}+qt4.dmg"
mv "${DMGLocation}/${DMGNAME}.dmg" "${DMGLocation}/${DMGNAME}+qt4.dmg"
for libnm in ${QtLibraries} ; do
fwdir=`framework_name "$libnm"`
rm -rf "${LyxAppDir}.app/Contents/${fwdir}"
done
make_dmg "${DMGLocation}"
fi
)

View File

@ -19,6 +19,7 @@
#include "support/debug.h"
#include "support/docstring_list.h"
#include "support/Package.h"
#include "support/FileName.h"
#include "support/Path.h"
@ -27,15 +28,41 @@
#include <map>
#include <string>
#ifdef __APPLE__
# ifndef ASPELL_FRAMEWORK
# define ASPELL_FRAMEWORK "Aspell.framework"
# endif
# ifndef ASPELL_FRAMEWORK_DATA
# define ASPELL_FRAMEWORK_DATA "/Resources/data"
# endif
# ifndef ASPELL_FRAMEWORK_DICT
# define ASPELL_FRAMEWORK_DICT "/Resources/dict"
# endif
# ifndef ASPELL_MACPORTS
# define ASPELL_MACPORTS "/opt/local"
# endif
# ifndef ASPELL_MACPORTS_DATA
# define ASPELL_MACPORTS_DATA "/lib/aspell-0.60"
# endif
# ifndef ASPELL_MACPORTS_DICT
# define ASPELL_MACPORTS_DICT "/share/aspell"
# endif
#endif /* __APPLE__ */
using namespace std;
using namespace lyx::support;
namespace lyx {
namespace {
struct Speller {
AspellSpeller * speller;
///AspellSpeller * speller;
AspellConfig * config;
AspellCanHaveError * e_speller;
};
typedef std::map<std::string, Speller> Spellers;
@ -44,7 +71,7 @@ typedef std::map<std::string, Speller> Spellers;
struct AspellChecker::Private
{
Private(): spell_error_object(0) {}
Private() {}
~Private();
@ -63,61 +90,91 @@ struct AspellChecker::Private
/// the spellers
Spellers spellers_;
/// FIXME
AspellCanHaveError * spell_error_object;
};
AspellChecker::Private::~Private()
{
if (spell_error_object) {
delete_aspell_can_have_error(spell_error_object);
spell_error_object = 0;
}
Spellers::iterator it = spellers_.begin();
Spellers::iterator end = spellers_.end();
for (; it != end; ++it) {
aspell_speller_save_all_word_lists(it->second.speller);
delete_aspell_speller(it->second.speller);
if (it->second.e_speller) {
AspellSpeller * speller = to_aspell_speller(it->second.e_speller);
aspell_speller_save_all_word_lists(speller);
delete_aspell_can_have_error(it->second.e_speller);
}
delete_aspell_config(it->second.config);
}
}
AspellConfig * getConfig()
bool isValidDictionary(AspellConfig * config,
string const & lang, string const & variety)
{
bool have = false;
// code taken from aspell's list-dicts example
// the returned pointer should _not_ need to be deleted
AspellDictInfoList * dlist = get_aspell_dict_info_list(config);
AspellDictInfoEnumeration * dels = aspell_dict_info_list_elements(dlist);
const AspellDictInfo * entry;
while (0 != (entry = aspell_dict_info_enumeration_next(dels))) {
LYXERR(Debug::DEBUG, "aspell dict:"
<< " name=" << entry->name
<< ",code=" << entry->code
<< ",variety=" << entry->jargon);
if (entry->code == lang && (variety.empty() || entry->jargon == variety)) {
have = true;
break;
}
}
delete_aspell_dict_info_enumeration(dels);
LYXERR(Debug::FILES, "aspell dictionary: " << lang << (have ? " yes" : " no"));
return have;
}
bool checkAspellData(AspellConfig * config,
char const * basepath, char const * datapath, char const * dictpath,
string const & lang, string const & variety)
{
bool have_dict = false;
FileName base(basepath);
FileName data(base.absFileName() + datapath);
FileName dict(base.absFileName() + dictpath);
have_dict = dict.isDirectory() && data.isDirectory();
if (have_dict) {
aspell_config_replace(config, "dict-dir", dict.absFileName().c_str());
aspell_config_replace(config, "data-dir", data.absFileName().c_str());
LYXERR(Debug::FILES, "aspell dict: " << dict);
have_dict = isValidDictionary(config, lang, variety);
}
return have_dict ;
}
AspellConfig * getConfig(string const & lang,
string const & variety)
{
AspellConfig * config = new_aspell_config();
#ifdef __APPLE__
char buf[2048] ;
bool have_dict = false;
#ifdef ASPELL_FRAMEWORK
char * framework = ASPELL_FRAMEWORK ;
char const * sysdir = lyx::support::package().system_support().absFileName().c_str() ;
char const * userdir = lyx::support::package().user_support().absFileName().c_str() ;
char const * framework = ASPELL_FRAMEWORK ;
if ( strlen(framework) && getPrivateFrameworkPathName(buf, sizeof(buf), framework) ) {
lyx::support::FileName const base(buf);
lyx::support::FileName const data(base.absFileName() + "/Resources/data");
lyx::support::FileName const dict(base.absFileName() + "/Resources/dict");
LYXERR(Debug::FILES, "aspell sysdir dir: " << sysdir);
LYXERR(Debug::FILES, "aspell user dir: " << userdir);
have_dict = checkAspellData(config, userdir, ASPELL_FRAMEWORK_DATA, ASPELL_FRAMEWORK_DICT, lang, variety);
if (!have_dict && strlen(framework) && getPrivateFrameworkPathName(buf, sizeof(buf), framework)) {
LYXERR(Debug::FILES, "aspell bundle path: " << buf);
have_dict = dict.isDirectory() && data.isDirectory();
if (have_dict) {
aspell_config_replace(config, "dict-dir", dict.absFileName().c_str());
aspell_config_replace(config, "data-dir", data.absFileName().c_str());
LYXERR(Debug::FILES, "aspell dict: " << dict);
}
have_dict = checkAspellData(config, buf, ASPELL_FRAMEWORK_DATA, ASPELL_FRAMEWORK_DICT, lang, variety);
}
#endif
if ( !have_dict ) {
lyx::support::FileName const base("/opt/local"); // check for mac-ports data
lyx::support::FileName const data(base.absFileName() + "/lib/aspell-0.60");
lyx::support::FileName const dict(base.absFileName() + "/share/aspell");
have_dict = dict.isDirectory() && data.isDirectory();
if (have_dict) {
aspell_config_replace(config, "dict-dir", dict.absFileName().c_str());
aspell_config_replace(config, "data-dir", data.absFileName().c_str());
LYXERR(Debug::FILES, "aspell dict: " << dict);
}
if (!have_dict) {
// check for macports data
have_dict = checkAspellData(config, ASPELL_MACPORTS, ASPELL_MACPORTS_DATA, ASPELL_MACPORTS_DICT, lang, variety);
}
#endif
return config ;
@ -127,13 +184,15 @@ AspellConfig * getConfig()
AspellSpeller * AspellChecker::Private::addSpeller(string const & lang,
string const & variety)
{
AspellConfig * config = getConfig();
Speller m;
m.config = getConfig(lang, variety);
// Aspell supports both languages and varieties (such as German
// old vs. new spelling). The respective naming convention is
// lang_REGION-variety (e.g. de_DE-alt).
aspell_config_replace(config, "lang", lang.c_str());
aspell_config_replace(m.config, "lang", lang.c_str());
if (!variety.empty())
aspell_config_replace(config, "variety", variety.c_str());
aspell_config_replace(m.config, "variety", variety.c_str());
// Set the encoding to utf-8.
// aspell does also understand "ucs-4", so we would not need a
// conversion in theory, but if this is used it expects all
@ -141,31 +200,22 @@ AspellSpeller * AspellChecker::Private::addSpeller(string const & lang,
// seems that this uint is not compatible with our char_type on some
// platforms (cygwin, OS X). Therefore we use utf-8, that does
// always work.
aspell_config_replace(config, "encoding", "utf-8");
aspell_config_replace(m.config, "encoding", "utf-8");
if (lyxrc.spellchecker_accept_compound)
// Consider run-together words as legal compounds
aspell_config_replace(config, "run-together", "true");
aspell_config_replace(m.config, "run-together", "true");
else
// Report run-together words as errors
aspell_config_replace(config, "run-together", "false");
aspell_config_replace(m.config, "run-together", "false");
AspellCanHaveError * err = new_aspell_speller(config);
if (spell_error_object)
delete_aspell_can_have_error(spell_error_object);
spell_error_object = 0;
if (aspell_error_number(err) != 0) {
// FIXME: We should we indicate somehow that this language is not
// supported.
spell_error_object = err;
LYXERR(Debug::FILES, "aspell error: " << aspell_error_message(err));
return 0;
m.e_speller = new_aspell_speller(m.config);
if (aspell_error_number(m.e_speller) != 0) {
// FIXME: We should indicate somehow that this language is not supported.
LYXERR(Debug::FILES, "aspell error: " << aspell_error_message(m.e_speller));
}
Speller m;
m.speller = to_aspell_speller(err);
m.config = config;
spellers_[spellerID(lang, variety)] = m;
return m.speller;
return to_aspell_speller(m.e_speller);
}
@ -174,7 +224,7 @@ AspellSpeller * AspellChecker::Private::speller(string const & lang,
{
Spellers::iterator it = spellers_.find(spellerID(lang, variety));
if (it != spellers_.end())
return it->second.speller;
return to_aspell_speller(it->second.e_speller);
return addSpeller(lang, variety);
}
@ -224,8 +274,10 @@ void AspellChecker::insert(WordLangTuple const & word)
{
Spellers::iterator it = d->spellers_.find(
d->spellerID(word.lang()->code(), word.lang()->variety()));
if (it != d->spellers_.end())
aspell_speller_add_to_personal(it->second.speller, to_utf8(word.word()).c_str(), -1);
if (it != d->spellers_.end()) {
AspellSpeller * speller = to_aspell_speller(it->second.e_speller);
aspell_speller_add_to_personal(speller, to_utf8(word.word()).c_str(), -1);
}
}
@ -233,8 +285,10 @@ void AspellChecker::accept(WordLangTuple const & word)
{
Spellers::iterator it = d->spellers_.find(
d->spellerID(word.lang()->code(), word.lang()->variety()));
if (it != d->spellers_.end())
aspell_speller_add_to_session(it->second.speller, to_utf8(word.word()).c_str(), -1);
if (it != d->spellers_.end()) {
AspellSpeller * speller = to_aspell_speller(it->second.e_speller);
aspell_speller_add_to_session(speller, to_utf8(word.word()).c_str(), -1);
}
}
@ -268,46 +322,34 @@ void AspellChecker::suggest(WordLangTuple const & wl,
bool AspellChecker::hasDictionary(Language const * lang) const
{
if (!lang)
return false;
// code taken from aspell's list-dicts example
AspellConfig * config;
AspellDictInfoList * dlist;
AspellDictInfoEnumeration * dels;
const AspellDictInfo * entry;
config = getConfig();
/* the returned pointer should _not_ need to be deleted */
dlist = get_aspell_dict_info_list(config);
/* config is no longer needed */
delete_aspell_config(config);
dels = aspell_dict_info_list_elements(dlist);
bool have = false;
while ((entry = aspell_dict_info_enumeration_next(dels)) != 0)
{
if (entry->code == lang->code()
&& (lang->variety().empty() || entry->jargon == lang->variety())) {
have = true;
break;
Spellers::iterator it = d->spellers_.begin();
Spellers::iterator end = d->spellers_.end();
if (lang) {
for (; it != end && !have; ++it) {
have = isValidDictionary(it->second.config, lang->code(), lang->variety());
}
if (!have) {
AspellConfig * config = getConfig(lang->code(), lang->variety());
have = isValidDictionary(config, lang->code(), lang->variety());
delete_aspell_config(config);
}
}
delete_aspell_dict_info_enumeration(dels);
return have;
}
docstring const AspellChecker::error()
{
Spellers::iterator it = d->spellers_.begin();
Spellers::iterator end = d->spellers_.end();
char const * err = 0;
if (d->spell_error_object && aspell_error_number(d->spell_error_object) != 0)
err = aspell_error_message(d->spell_error_object);
for (; it != end && 0 == err; ++it) {
if (it->second.e_speller && aspell_error_number(it->second.e_speller) != 0)
err = aspell_error_message(it->second.e_speller);
}
// FIXME UNICODE: err is not in UTF8, but probably the locale encoding
return (err ? from_utf8(err) : docstring());

View File

@ -20,6 +20,7 @@
#include "support/debug.h"
#include "support/docstring_list.h"
#include "support/filetools.h"
#include "support/Package.h"
#include "support/FileName.h"
#include "support/gettext.h"
#include "support/lassert.h"
@ -45,6 +46,10 @@ typedef vector<WordLangTuple> IgnoreList;
} // anon namespace
#ifndef HUNSPELL_DICT
# define HUNSPELL_DICT "dict"
#endif
struct HunspellChecker::Private
{
Private() {}
@ -52,6 +57,8 @@ struct HunspellChecker::Private
~Private();
bool haveDictionary(string const & lang, string & hpath);
bool haveDictionary(string const & lang);
Hunspell * addSpeller(string const & lang, string & hpath);
Hunspell * addSpeller(string const & lang);
Hunspell * speller(string const & lang);
/// ignored words
@ -70,7 +77,7 @@ HunspellChecker::Private::~Private()
Spellers::iterator end = spellers_.end();
for (; it != end; ++it) {
delete it->second;
if ( 0 != it->second) delete it->second;
}
}
@ -80,67 +87,59 @@ bool haveLanguageFiles(string const & hpath)
{
FileName const affix(hpath + ".aff");
FileName const dict(hpath + ".dic");
if (!affix.isReadableFile()) {
// FIXME: We should indicate somehow that this language is not
// supported.
LYXERR(Debug::FILES, "Hunspell affix file " << affix << " does not exist");
return false;
}
if (!dict.isReadableFile()) {
LYXERR(Debug::FILES, "Hunspell dictionary file " << dict << " does not exist");
return false;
}
return true;
}
return affix.isReadableFile() && dict.isReadableFile();
}
bool HunspellChecker::Private::haveDictionary(string const & lang, string & hunspell_path)
#define MAX_SELECTOR 3
string dictPath(int selector)
{
LYXERR(Debug::FILES, "hunspell path: " << external_path(hunspell_path));
if (hunspell_path.empty()) {
// FIXME We'd like to issue a better error message here, but there seems
// to be a problem about thread safety, or something of the sort. If
// we issue the message using frontend::Alert, then the code comes
// back through here while the box is waiting, and causes some kind
// of crash.
static bool warned = false;
if (!warned) {
warned = true;
LYXERR0("Hunspell path not set.");
//frontend::Alert::error(_("Hunspell Path Not Found"),
// _("You must set the Hunspell dictionary path in Tools>Preferences>Paths."));
}
switch (selector) {
case 2:
return addName(lyx::support::package().system_support().absFileName(),HUNSPELL_DICT);
break;
case 1:
return addName(lyx::support::package().user_support().absFileName(),HUNSPELL_DICT);
break;
default:
return lyxrc.hunspelldir_path;
}
}
}
bool HunspellChecker::Private::haveDictionary(string const & lang, string & hpath)
{
if (hpath.empty()) {
return false;
}
hunspell_path = external_path(addName(hunspell_path, lang));
if (!haveLanguageFiles(hunspell_path)) {
LYXERR(Debug::FILES, "check hunspell path: " << hpath << " for language " << lang);
string h_path = addName(hpath, lang);
if (!haveLanguageFiles(h_path)) {
// try with '_' replaced by '-'
hunspell_path = subst(hunspell_path, '_', '-');
if (!haveLanguageFiles(hunspell_path)) {
h_path = addName(hpath, subst(lang, '_', '-'));
if (!haveLanguageFiles(h_path)) {
// FIXME: We should indicate somehow that this language is not
// supported, probably by popping a warning. But we'll need to
// remember which warnings we've issued.
return false;
}
}
hpath = h_path;
return true;
}
Hunspell * HunspellChecker::Private::addSpeller(string const & lang)
bool HunspellChecker::Private::haveDictionary(string const & lang)
{
string hunspell_path = lyxrc.hunspelldir_path;
if (!haveDictionary(lang, hunspell_path))
return 0;
FileName const affix(hunspell_path + ".aff");
FileName const dict(hunspell_path + ".dic");
Hunspell * h = new Hunspell(affix.absFileName().c_str(), dict.absFileName().c_str());
spellers_[lang] = h;
return h;
bool result = false;
for ( int p = 0; !result && p < MAX_SELECTOR; p++ ) {
string lpath = dictPath(p);
result = haveDictionary(lang, lpath);
}
return result;
}
@ -154,6 +153,33 @@ Hunspell * HunspellChecker::Private::speller(string const & lang)
}
Hunspell * HunspellChecker::Private::addSpeller(string const & lang,string & path)
{
if (!haveDictionary(lang, path)) {
spellers_[lang] = 0;
return 0;
}
FileName const affix(path + ".aff");
FileName const dict(path + ".dic");
Hunspell * h = new Hunspell(affix.absFileName().c_str(), dict.absFileName().c_str());
LYXERR(Debug::FILES, "Hunspell speller for langage " << lang << " at " << dict << " found");
spellers_[lang] = h;
return h;
}
Hunspell * HunspellChecker::Private::addSpeller(string const & lang)
{
Hunspell * h = 0;
for ( int p = 0; p < MAX_SELECTOR && 0 == h; p++ ) {
string lpath = dictPath(p);
h = addSpeller(lang, lpath);
}
return h;
}
bool HunspellChecker::Private::isIgnored(WordLangTuple const & wl) const
{
IgnoreList::const_iterator it = ignored_.begin();
@ -246,8 +272,7 @@ bool HunspellChecker::hasDictionary(Language const * lang) const
{
if (!lang)
return false;
string hunspell_path = lyxrc.hunspelldir_path;
return (d->haveDictionary(lang->code(), hunspell_path));
return (d->haveDictionary(lang->code()));
}

View File

@ -16,6 +16,7 @@
#include "LyXRC.h"
#include "support/FileNameList.h"
#include "support/Package.h"
#include "support/debug.h"
#include "support/filetools.h"
#include "support/gettext.h"
@ -41,6 +42,9 @@ typedef std::map<docstring, MyThes *> Thesauri;
} // namespace anon
#ifndef THESAURUS_LOCATION
# define THESAURUS_LOCATION "thes"
#endif
struct Thesaurus::Private
{
@ -66,6 +70,7 @@ struct Thesaurus::Private
///
typedef std::pair<std::string, std::string> ThesFiles;
///
ThesFiles getThesaurus(string const & path, docstring const & lang);
ThesFiles getThesaurus(docstring const & lang);
/// add a thesaurus to the list
bool addThesaurus(docstring const & lang);
@ -75,45 +80,62 @@ struct Thesaurus::Private
};
pair<string, string> Thesaurus::Private::getThesaurus(docstring const & lang)
pair<string,string> Thesaurus::Private::getThesaurus(string const & path, docstring const & lang)
{
string const thes_path = external_path(lyxrc.thesaurusdir_path);
LYXERR(Debug::FILES, "thesaurus path: " << thes_path);
if (thes_path.empty())
FileName base(path);
if (!base.isDirectory()) {
return make_pair(string(), string());
if (thesaurusAvailable(lang))
return make_pair(string(), string());
FileNameList const idx_files = FileName(thes_path).dirList("idx");
FileNameList const data_files = FileName(thes_path).dirList("dat");
}
FileNameList const idx_files = base.dirList("idx");
FileNameList const data_files = base.dirList("dat");
string idx;
string data;
for (FileNameList::const_iterator it = idx_files.begin();
it != idx_files.end(); ++it) {
LYXERR(Debug::FILES, "found thesaurus idx file: " << it->onlyFileName());
LYXERR(Debug::FILES, "thesaurus path: " << path);
for (FileNameList::const_iterator it = idx_files.begin(); it != idx_files.end(); ++it) {
if (contains(it->onlyFileName(), to_ascii(lang))) {
idx = it->absFileName();
LYXERR(Debug::FILES, "selected thesaurus idx file: " << idx);
break;
}
}
for (support::FileNameList::const_iterator it = data_files.begin();
it != data_files.end(); ++it) {
LYXERR(Debug::FILES, "found thesaurus data file: " << it->onlyFileName());
}
if (idx.empty()) {
return make_pair(string(), string());
}
for (support::FileNameList::const_iterator it = data_files.begin(); it != data_files.end(); ++it) {
if (contains(it->onlyFileName(), to_ascii(lang))) {
data = it->absFileName();
LYXERR(Debug::FILES, "selected thesaurus data file: " << data);
break;
}
}
}
return make_pair(idx, data);
}
pair<string,string> Thesaurus::Private::getThesaurus(docstring const & lang)
{
string const thes_path = external_path(lyxrc.thesaurusdir_path);
pair<string,string> result ;
if (thesaurusAvailable(lang))
return make_pair(string(), string());
if (!thes_path.empty()) {
result = getThesaurus(thes_path, lang);
}
if (result.first.empty() || result.second.empty()) {
string const sys_path = external_path(addName(lyx::support::package().system_support().absFileName(),THESAURUS_LOCATION)) ;
result = getThesaurus(sys_path, lang);
}
if (result.first.empty() || result.second.empty()) {
string const user_path = external_path(addName(lyx::support::package().user_support().absFileName(),THESAURUS_LOCATION)) ;
result = getThesaurus(user_path, lang);
}
return result;
}
bool Thesaurus::Private::addThesaurus(docstring const & lang)
{
if (thesaurusAvailable(lang))